fix(sheets-data-validation): date data validation format not work & optimize popup-service (#3018)

This commit is contained in:
zhangw
2024-08-14 11:21:36 +08:00
committed by GitHub
parent 2e475b3276
commit 92dedd660c
52 changed files with 387 additions and 370 deletions
@@ -97,7 +97,7 @@ function updateTextRuns(
return removeTextRuns;
}
// eslint-disable-next-line max-lines-per-function
// eslint-disable-next-line max-lines-per-function, complexity
export function coverTextRuns(
updateDataTextRuns: ITextRun[],
removeTextRuns: ITextRun[],
@@ -202,7 +202,7 @@ export function coverTextRuns(
const updateLastTextRun = updateDataTextRuns[updateLength - 1];
const removeLastTextRun = removeTextRuns[removeLength - 1];
if (tempTopTextRun.ed !== Math.max(updateLastTextRun.ed, removeLastTextRun.ed)) {
if (tempTopTextRun && (tempTopTextRun.ed !== Math.max(updateLastTextRun.ed, removeLastTextRun.ed))) {
if (updateLastTextRun.ed > removeLastTextRun.ed) {
newUpdateTextRuns.push(updateLastTextRun);
} else {
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import type { CellValue, IDataValidationRule, IDataValidationRuleBase, Nullable } from '@univerjs/core';
import type { CellValue, IDataValidationRule, IDataValidationRuleBase, Nullable, Workbook, Worksheet } from '@univerjs/core';
import { DataValidationOperator, Inject, Injector, LocaleService, Tools } from '@univerjs/core';
import { OperatorErrorTitleMap, OperatorTitleMap } from '../types/const/operator-text-map';
import type { IBaseDataValidationWidget } from './base-widget';
@@ -39,6 +39,8 @@ export interface IValidatorCellInfo<DataType = Nullable<CellValue>> {
column: number;
unitId: string;
subUnitId: string;
worksheet: Worksheet;
workbook: Workbook;
}
export interface IFormulaResult<T = any> {
@@ -107,7 +109,7 @@ export abstract class BaseDataValidator<DataType = CellValue> {
}
getRuleFinalError(rule: IDataValidationRule) {
if (rule.showInputMessage && rule.error) {
if (rule.showErrorMessage && rule.error) {
return rule.error;
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { CommandType, CustomRangeType, generateRandomId, type ICommand, ICommandService, sequenceExecuteAsync } from '@univerjs/core';
import { CommandType, CustomRangeType, generateRandomId, type ICommand, ICommandService, sequenceExecute } from '@univerjs/core';
import { addCustomRangeBySelectionFactory } from '@univerjs/docs';
import { AddDocHyperLinkMutation } from '@univerjs/docs-hyper-link';
@@ -47,7 +47,7 @@ export const AddDocHyperLinkCommand: ICommand<IAddDocHyperLinkCommandParams> = {
params: { unitId, link: { payload, id } },
};
return (await sequenceExecuteAsync([hyperLinkMutation, doMutation], commandService)).result;
return (await sequenceExecute([hyperLinkMutation, doMutation], commandService)).result;
}
return false;
@@ -49,8 +49,8 @@ export class DocHyperLinkClipboardController extends Disposable {
customRanges?.find(
(range) =>
range.rangeType === CustomRangeType.HYPERLINK &&
range.startIndex <= activeRange.startOffset &&
range.endIndex >= activeRange.endOffset - 1
range.startIndex < activeRange.startOffset &&
range.endIndex > activeRange.endOffset - 1
)
: null;
// insert into current link inside
@@ -57,9 +57,7 @@ export function transformPosition2Offset(x: number, y: number, scene: Scene) {
};
}
export interface IDocCanvasPopup extends Pick<IPopup,
'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside'
> {
export interface IDocCanvasPopup extends Pick<IPopup, 'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside' | 'hideOnInvisible'> {
mask?: boolean;
extraProps?: Record<string, any>;
}
@@ -223,6 +221,7 @@ export class DocCanvasPopManagerService extends Disposable {
subUnitId: 'default',
anchorRect: position,
anchorRect$: position$,
canvasElement: currentRender.engine.getCanvasElement(),
});
return {
@@ -259,6 +258,7 @@ export class DocCanvasPopManagerService extends Disposable {
excludeRects: bounds,
excludeRects$: bounds$,
direction: direction === 'top' ? 'top' : 'bottom',
canvasElement: currentRender.engine.getCanvasElement(),
});
return {
+7 -4
View File
@@ -30,7 +30,8 @@ export function getRetainAndDeleteAndExcludeLineBreak(
selection: ITextRange,
body: IDocumentBody,
segmentId: string = '',
memoryCursor: number = 0
memoryCursor: number = 0,
preserveLineBreak: boolean = true
): Array<IRetainAction | IDeleteAction> {
const { startOffset, endOffset } = getDeleteSelection(selection, body);
const dos: Array<IRetainAction | IDeleteAction> = [];
@@ -73,9 +74,11 @@ export function getRetainAndDeleteAndExcludeLineBreak(
});
}
if (paragraphInRange && paragraphInRange.startIndex - memoryCursor > textStart) {
const paragraphIndex = paragraphInRange.startIndex - memoryCursor;
retainPoints.add(paragraphIndex);
if (preserveLineBreak) {
if (paragraphInRange && paragraphInRange.startIndex - memoryCursor > textStart) {
const paragraphIndex = paragraphInRange.startIndex - memoryCursor;
retainPoints.add(paragraphIndex);
}
}
const sortedRetains = [...retainPoints].sort((pre, aft) => pre - aft);
@@ -209,7 +209,7 @@ function getCutActionsFromTextRanges(
segmentId,
});
} else {
textX.push(...getRetainAndDeleteAndExcludeLineBreak(selection, originBody, segmentId, memoryCursor.cursor));
textX.push(...getRetainAndDeleteAndExcludeLineBreak(selection, originBody, segmentId, memoryCursor.cursor, false));
}
memoryCursor.reset();
@@ -393,7 +393,6 @@ export const CutContentCommand: ICommand<IInnerCutCommandParams> = {
const commandService = accessor.get(ICommandService);
const textSelectionManagerService = accessor.get(TextSelectionManagerService);
const univerInstanceService = accessor.get(IUniverInstanceService);
const selections = params.selections ?? textSelectionManagerService.getCurrentTextRanges();
const rectRanges = textSelectionManagerService.getCurrentRectRanges();
@@ -434,7 +433,6 @@ export const CutContentCommand: ICommand<IInnerCutCommandParams> = {
if (Array.isArray(selections) && selections?.length !== 0) {
doMutation.params.actions = getCutActionsFromTextRanges(selections, docDataModel, segmentId);
}
if (Array.isArray(rectRanges) && rectRanges?.length !== 0) {
const actions = getCutActionsFromRectRanges(rectRanges, docDataModel, viewModel, segmentId);
if (doMutation.params.actions?.length === 0 || doMutation.params.actions == null) {
@@ -194,7 +194,7 @@ export const ReplaceSelectionCommand: ICommand<IReplaceSelectionCommandParams> =
const textX = new TextX();
const jsonX = JSONX.getInstance();
// delete
textX.push(...getRetainAndDeleteAndExcludeLineBreak(selection, body));
textX.push(...getRetainAndDeleteAndExcludeLineBreak(selection, body, '', 0, false));
// insert
textX.push({
t: TextXActionType.INSERT,
@@ -42,7 +42,7 @@ export class DataValidationRejectInputController extends Disposable {
{
handler: async (cellPromise, context, next) => {
const cell = await cellPromise;
const { worksheet, row, col, unitId, subUnitId } = context;
const { worksheet, row, col, unitId, subUnitId, workbook } = context;
const manager = this._dataValidationModel.ensureManager(unitId, subUnitId) as SheetDataValidationManager;
const ruleId = manager.getRuleIdByLocation(row, col);
const rule = ruleId ? manager.getRuleById(ruleId) : undefined;
@@ -62,6 +62,8 @@ export class DataValidationRejectInputController extends Disposable {
column: col,
unitId,
subUnitId,
worksheet,
workbook,
}, rule
);
@@ -15,12 +15,11 @@
*/
import type { Workbook } from '@univerjs/core';
import { DisposableCollection, Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, RxDisposable, toDisposable, UniverInstanceType } from '@univerjs/core';
import { Inject, Injector, IUniverInstanceService, LifecycleStages, OnLifecycle, RxDisposable, UniverInstanceType } from '@univerjs/core';
import { DataValidationModel, DataValidatorRegistryService } from '@univerjs/data-validation';
import { DataValidationSingle } from '@univerjs/icons';
import { ComponentManager } from '@univerjs/ui';
import { ClearSelectionAllCommand, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets';
import { SheetDataValidationService } from '../services/dv.service';
import { CustomFormulaValidator } from '../validators/custom-validator';
import { CheckboxValidator, DateValidator, DecimalValidator, ListValidator, TextLengthValidator } from '../validators';
import { WholeValidator } from '../validators/whole-validator';
@@ -39,7 +38,6 @@ import { DataValidationIcon } from './dv.menu';
export class DataValidationController extends RxDisposable {
constructor(
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@Inject(SheetDataValidationService) private readonly _sheetDataValidationService: SheetDataValidationService,
@Inject(DataValidatorRegistryService) private readonly _dataValidatorRegistryService: DataValidatorRegistryService,
@Inject(Injector) private readonly _injector: Injector,
@Inject(ComponentManager) private readonly _componentManger: ComponentManager,
@@ -53,7 +51,6 @@ export class DataValidationController extends RxDisposable {
private _init() {
this._registerValidators();
this._initInstanceChange();
this._initCommandInterceptor();
this._initComponents();
}
@@ -81,33 +78,6 @@ export class DataValidationController extends RxDisposable {
});
}
private _initInstanceChange() {
const disposableCollection = new DisposableCollection();
this.disposeWithMe(this._univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET).subscribe((workbook) => {
disposableCollection.dispose();
if (!workbook) {
return;
}
const worksheet = workbook.getActiveSheet();
if (!worksheet) {
return;
}
this._sheetDataValidationService.switchCurrent(workbook.getUnitId(), worksheet.getSheetId());
disposableCollection.add(toDisposable(
workbook.activeSheet$.subscribe((worksheet) => {
if (worksheet) {
const unitId = workbook.getUnitId();
const subUnitId = worksheet.getSheetId();
this._sheetDataValidationService.switchCurrent(unitId, subUnitId);
}
})
));
}));
this.disposeWithMe(disposableCollection);
}
private _initCommandInterceptor() {
this._sheetInterceptorService.interceptCommand({
getMutations: (commandInfo) => {
@@ -16,19 +16,10 @@
export { UniverSheetsDataValidationPlugin } from './plugin';
export { UniverSheetsDataValidationMobilePlugin } from './mobile-plugin';
export { SheetsDataValidationRenderController } from './controllers/dv-render.controller';
export { DataValidationController } from './controllers/dv.controller';
export { SheetDataValidationService } from './services/dv.service';
export { DataValidationAlertController } from './controllers/dv-alert.controller';
export { DataValidationCacheService } from './services/dv-cache.service';
export { DataValidationFormulaService } from './services/dv-formula.service';
export { DataValidationCustomFormulaService } from './services/dv-custom-formula.service';
export { DataValidationRefRangeController } from './controllers/dv-ref-range.controller';
export { DATA_VALIDATION_PLUGIN_NAME } from './common/const';
export { DataValidationAutoFillController } from './controllers/dv-auto-fill.controller';
export { DataValidationCopyPasteController } from './controllers/dv-copy-paste.controller';
export { DataValidationRejectInputController } from './controllers/dv-reject-input.controller';
export { DataValidationFormulaController } from './controllers/dv-formula.controller';
export { SheetsDataValidationValidatorService } from './services/dv-validator-service';
// #region - all commands
@@ -107,14 +107,14 @@ const locale: typeof zhCN = {
notBetween: 'is not between {FORMULA1}',
},
errorMsg: {
between: 'Value must be between {FORMULA1} and {FORMULA2}',
greaterThan: 'Value must be after {FORMULA1}',
greaterThanOrEqual: 'Value must be on or after {FORMULA1}',
lessThan: 'Value must be before {FORMULA1}',
lessThanOrEqual: 'Value must be on or before {FORMULA1}',
equal: 'Value must be {FORMULA1}',
notEqual: 'Value must be not {FORMULA1}',
notBetween: 'Value must be not between {FORMULA1}',
between: 'Value must be a legal date and between {FORMULA1} and {FORMULA2}',
greaterThan: 'Value must be a legal date and after {FORMULA1}',
greaterThanOrEqual: 'Value must be a legal date and on or after {FORMULA1}',
lessThan: 'Value must be a legal date and before {FORMULA1}',
lessThanOrEqual: 'Value must be a legal date and on or before {FORMULA1}',
equal: 'Value must be a legal date and {FORMULA1}',
notEqual: 'Value must be a legal date and not {FORMULA1}',
notBetween: 'Value must be a legal date and not between {FORMULA1}',
},
},
list: {
@@ -128,6 +128,7 @@ const locale: typeof zhCN = {
customOptions: 'Custom',
refOptions: 'From a range',
formulaError: 'The list source must be a delimited list of data, or a reference to a single row or column.',
edit: 'Edit',
},
listMultiple: {
title: 'Dropdown-Multiple',
@@ -128,6 +128,7 @@ const locale: typeof zhCN = {
customOptions: 'Пользовательские',
refOptions: 'Из диапазона',
formulaError: 'Источник списка должен быть разделенным списком данных или ссылкой на одну строку или столбец.',
edit: 'Редактировать',
},
listMultiple: {
title: 'Выпадающий список - Множественный',
@@ -128,6 +128,7 @@ const locale: typeof zhCN = {
customOptions: 'Tùy chỉnh',
refOptions: 'Tham chiếu dữ liệu',
formulaError: 'Nguồn danh sách phải là danh sách dữ liệu đã được phân chia rõ ràng, hoặc là tham chiếu đến một hàng hoặc cột đơn.',
edit: 'Biên tập',
},
listMultiple: {
title: 'Danh sách thả xuống - Chọn nhiều',
@@ -105,14 +105,14 @@ const locale = {
notBetween: '在 {FORMULA1} 和 {FORMULA2} 范围之外',
},
errorMsg: {
between: '日期必须介于 {FORMULA1} 和 {FORMULA2} 之间',
greaterThan: '日期必须晚于 {FORMULA1}',
greaterThanOrEqual: '日期必须晚于或等于 {FORMULA1}',
lessThan: '日期必须早于 {FORMULA1}',
lessThanOrEqual: '早于或等于 {FORMULA1}',
equal: '日期必须等于 {FORMULA1}',
notEqual: '日期必须不等于 {FORMULA1}',
notBetween: '日期必须在 {FORMULA1} 和 {FORMULA2} 范围之外',
between: '必须为有效日期且介于 {FORMULA1} 和 {FORMULA2} 之间',
greaterThan: '必须为有效日期且晚于 {FORMULA1}',
greaterThanOrEqual: '必须为有效日期且晚于或等于 {FORMULA1}',
lessThan: '必须为有效日期且早于 {FORMULA1}',
lessThanOrEqual: '必须为有效日期且早于或等于 {FORMULA1}',
equal: '必须为有效日期且等于 {FORMULA1}',
notEqual: '必须为有效日期且不等于 {FORMULA1}',
notBetween: '必须为有效日期且在 {FORMULA1} 和 {FORMULA2} 范围之外',
},
},
list: {
@@ -128,6 +128,7 @@ const locale = {
customOptions: '自定义',
refOptions: '引用数据',
formulaError: '列表源必须是划定分界后的数据列表,或是对单一行或一列的引用。',
edit: '编辑',
},
listMultiple: {
title: '下拉菜单-多选',
@@ -130,6 +130,7 @@ const locale: typeof zhCN = {
customOptions: '自訂',
refOptions: '引用資料',
formulaError: '列表來源必須是劃定分界後的資料列表,或是對單一行或一列的引用。 ',
edit: '編輯',
},
listMultiple: {
title: '下拉式選單-多選',
@@ -22,7 +22,6 @@ import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';
import type { IUniverSheetsDataValidation } from './controllers/dv-render.controller';
import { DefaultSheetsDataValidation, SheetsDataValidationMobileRenderController } from './controllers/dv-render.controller';
import { DataValidationController } from './controllers/dv.controller';
import { SheetDataValidationService } from './services/dv.service';
import { DataValidationAlertController } from './controllers/dv-alert.controller';
import { AddSheetDataValidationAndOpenCommand, AddSheetDataValidationCommand, UpdateSheetDataValidationRangeCommand } from './commands/commands/data-validation.command';
import { DataValidationCacheService } from './services/dv-cache.service';
@@ -58,7 +57,6 @@ export class UniverSheetsDataValidationMobilePlugin extends Plugin {
override onStarting() {
([
[DataValidationPanelService],
[SheetDataValidationService],
[DataValidationCacheService],
[DataValidationFormulaService],
[DataValidationCustomFormulaService],
@@ -18,7 +18,7 @@ import type { CellValue, Injector, ISheetDataValidationRule, Nullable, Workbook
import { DataValidationManager, DataValidatorRegistryService, UpdateRuleType } from '@univerjs/data-validation';
import { DataValidationStatus, DataValidationType, IUniverInstanceService, ObjectMatrix, UniverInstanceType } from '@univerjs/core';
import type { IUpdateRulePayload } from '@univerjs/data-validation';
import type { ISheetLocationBase } from '@univerjs/sheets';
import type { ISheetLocation } from '@univerjs/sheets';
import { isReferenceString } from '@univerjs/engine-formula';
import type { IDataValidationResCache } from '../services/dv-cache.service';
import { DataValidationCacheService } from '../services/dv-cache.service';
@@ -128,7 +128,7 @@ export class SheetDataValidationManager extends DataValidationManager<ISheetData
return this.getRuleById(ruleId);
}
override validator(cellValue: Nullable<CellValue>, rule: ISheetDataValidationRule, pos: ISheetLocationBase, onCompete: (status: DataValidationStatus, changed: boolean) => void): DataValidationStatus {
override validator(cellValue: Nullable<CellValue>, rule: ISheetDataValidationRule, pos: ISheetLocation, onCompete: (status: DataValidationStatus, changed: boolean) => void): DataValidationStatus {
const { col, row, unitId, subUnitId } = pos;
const ruleId = rule.uid;
const validator = this.getValidator(rule.type);
@@ -140,7 +140,18 @@ export class SheetDataValidationManager extends DataValidationManager<ISheetData
status: DataValidationStatus.VALIDATING,
ruleId,
});
validator.validator({ value: cellValue, unitId, subUnitId, row, column: col }, rule).then((status) => {
validator.validator(
{
value: cellValue,
unitId,
subUnitId,
row,
column: col,
worksheet: pos.worksheet,
workbook: pos.workbook,
},
rule
).then((status) => {
const realStatus = status ? DataValidationStatus.VALID : DataValidationStatus.INVALID;
this._cache.setValue(row, col, {
value: cellValue,
@@ -22,7 +22,6 @@ import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';
import type { IUniverSheetsDataValidation } from './controllers/dv-render.controller';
import { DefaultSheetsDataValidation, SheetsDataValidationRenderController } from './controllers/dv-render.controller';
import { DataValidationController } from './controllers/dv.controller';
import { SheetDataValidationService } from './services/dv.service';
import { DataValidationAlertController } from './controllers/dv-alert.controller';
import { AddSheetDataValidationAndOpenCommand, AddSheetDataValidationCommand, UpdateSheetDataValidationOptionsCommand, UpdateSheetDataValidationRangeCommand, UpdateSheetDataValidationSettingCommand } from './commands/commands/data-validation.command';
import { DataValidationCacheService } from './services/dv-cache.service';
@@ -60,7 +59,6 @@ export class UniverSheetsDataValidationPlugin extends Plugin {
override onStarting() {
([
[DataValidationPanelService],
[SheetDataValidationService],
[DataValidationCacheService],
[DataValidationFormulaService],
[DataValidationCustomFormulaService],
@@ -80,7 +80,9 @@ export class DataValidationDropdownManagerService extends Disposable {
const { location } = param;
const { row, col } = location;
this._currentPopup && this._currentPopup.dispose();
if (this._currentPopup) {
this._currentPopup.dispose();
};
if (this._zenVisible) {
return;
@@ -50,7 +50,7 @@ export class SheetsDataValidationValidatorService {
}
return new Promise<DataValidationStatus>((resolve) => {
manager.validator(getCellValueOrigin(cellRaw), rule, { unitId, subUnitId, row, col }, resolve);
manager.validator(getCellValueOrigin(cellRaw), rule, { unitId, subUnitId, row, col, worksheet, workbook }, resolve);
});
}
@@ -1,71 +0,0 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Disposable, type Nullable } from '@univerjs/core';
import { Subject } from 'rxjs';
import { DataValidationModel } from '@univerjs/data-validation';
import { Inject } from '@univerjs/core';
import type { SheetDataValidationManager } from '../models/sheet-data-validation-manager';
export interface ICurrentDataValidationManager {
manager: SheetDataValidationManager;
unitId: string;
subUnitId: string;
}
export class SheetDataValidationService extends Disposable {
private _currentManager: Nullable<ICurrentDataValidationManager>;
private _currentManager$ = new Subject<ICurrentDataValidationManager>();
get currentManager() {
return this._currentManager;
}
currentManager$ = this._currentManager$.asObservable();
constructor(
@Inject(DataValidationModel) private _dataValidationModel: DataValidationModel
) {
// empty
super();
this.disposeWithMe(() => {
this._currentManager$.complete();
});
}
private _ensureManager(unitId: string, subUnitId: string) {
return this._dataValidationModel.ensureManager(unitId, subUnitId) as SheetDataValidationManager;
}
switchCurrent(unitId: string, subUnitId: string) {
if (unitId === this.currentManager?.unitId && subUnitId === this._currentManager?.subUnitId) {
return;
}
const manager = this._ensureManager(unitId, subUnitId);
this._currentManager = {
manager,
unitId,
subUnitId,
};
this._currentManager$.next(this._currentManager);
}
get(unitId: string, subUnitId: string) {
return this._ensureManager(unitId, subUnitId);
}
}
@@ -1,19 +0,0 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export class SheetDataValidationTipsService {
}
@@ -87,13 +87,19 @@ export class DateValidator extends BaseDataValidator<number> {
}
override async isValidType(info: IValidatorCellInfo): Promise<boolean> {
const { value } = info;
const { value, worksheet, row, column, workbook } = info;
if (typeof value === 'string') {
return dayjs(value, 'YYYY-MM-DD HH:mm:ss', true).isValid();
}
if (typeof value === 'number') {
return true;
const cell = worksheet.getCellRaw(row, column);
if (cell && cell.s) {
const style = workbook.getStyles().get(cell.s);
if (style?.n?.pattern.indexOf('yyyy-MM-dd') === 0) {
return true;
}
}
}
return false;
@@ -49,7 +49,7 @@ const transformDate = (value: Nullable<CellValue>) => {
export function DateDropdown(props: IDropdownComponentProps) {
const { location, hideFn } = props;
const { worksheet, row, col, unitId, subUnitId } = location;
const { worksheet, row, col, unitId, subUnitId, workbook } = location;
const commandService = useDependency(ICommandService);
const rejectInputController = useDependency(DataValidationRejectInputController);
const cellData = worksheet.getCell(row, col);
@@ -81,6 +81,8 @@ export function DateDropdown(props: IDropdownComponentProps) {
subUnitId,
row,
column: col,
worksheet,
workbook,
}, rule))
) {
commandService.executeCommand(SetRangeValuesCommand.id, {
@@ -44,6 +44,8 @@ interface ISelectListProps {
const SelectList = (props: ISelectListProps) => {
const { value, onChange, multiple, options, title, onEdit, style } = props;
const localeService = useDependency(LocaleService);
return (
<div className={styles.dvListDropdown} style={style}>
<div className={styles.dvListDropdownTitle}>
@@ -84,7 +86,7 @@ const SelectList = (props: ISelectListProps) => {
</div>
<div className={styles.dvListDropdownSplit} />
<div className={styles.dvListDropdownEdit}>
<a onClick={onEdit}>编辑</a>
<a onClick={onEdit}>{localeService.t('dataValidation.list.edit')}</a>
</div>
</div>
);
@@ -64,16 +64,16 @@ export function DataValidationOptions(props: IDataValidationOptionsParams) {
label={localeService.t('dataValidation.panel.messageInfo')}
>
<Checkbox
checked={value.showInputMessage}
checked={value.showErrorMessage}
onChange={() => onChange({
...value,
showInputMessage: !value.showInputMessage,
showErrorMessage: !value.showErrorMessage,
})}
>
{localeService.t('dataValidation.panel.showInfo')}
</Checkbox>
</FormLayout>
{value.showInputMessage
{value.showErrorMessage
? (
<FormLayout>
<Input value={value.error} onChange={(error) => onChange({ ...value, error })} />
+23
View File
@@ -30,6 +30,29 @@ import { UniverSheetsHyperLinkUIPlugin } from '@univerjs/sheets-hyper-link-ui';
univer.registerPlugin(UniverSheetsHyperLinkUIPlugin);
```
### API
```typescript
// All commands
import { AddHyperLinkCommand, type IAddHyperLinkCommandParams } from '@univerjs/sheets-hyper-link-ui';
import { RemoveHyperLinkCommand, CancelHyperLinkCommand, type IRemoveHyperLinkCommandParams } from '@univerjs/sheets-hyper-link-ui';
import { UpdateHyperLinkCommand, type IUpdateHyperLinkCommandParams } from '@univerjs/sheets-hyper-link-ui';
// Add hyperlink by command
const commandService = univer.__getInjector().get(ICommandService);
commandService.executeCommand(AddHyperLinkCommand.id, {
unitId: 'unitId',
subUnitId: 'subUnitId',
link: {
// comment content
payload: 'https://univer.ai',
id: '1',
row: 0,
column: 0
},
} as IAddCommentCommandParams);
```
<!-- Links -->
[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-hyper-link-ui?style=flat-square
[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-hyper-link-ui
@@ -17,16 +17,17 @@
import type { ICommand, IMutationInfo } from '@univerjs/core';
import { CommandType, ICommandService, IUndoRedoService, sequenceExecuteAsync } from '@univerjs/core';
import { SheetInterceptorService } from '@univerjs/sheets';
import type { ICellHyperLink } from '../../types/interfaces/i-hyper-link';
import { AddHyperLinkMutation } from '../mutations/add-hyper-link.mutation';
import { RemoveHyperLinkMutation } from '../mutations/remove-hyper-link.mutation';
import type { ICellHyperLink } from '@univerjs/sheets-hyper-link';
import { AddHyperLinkMutation, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link';
export interface IAddHyperLinkCommandParams {
unitId: string;
subUnitId: string;
link: ICellHyperLink;
}
/**
* Command for add hyperlink
*/
export const AddHyperLinkCommand: ICommand<IAddHyperLinkCommandParams> = {
type: CommandType.COMMAND,
id: 'sheets.command.add-hyper-link',
@@ -17,14 +17,15 @@
import type { ICommand, IMutationInfo } from '@univerjs/core';
import { CommandType, ICommandService, IUndoRedoService, sequenceExecuteAsync } from '@univerjs/core';
import { SheetInterceptorService } from '@univerjs/sheets';
import type { IAddHyperLinkMutationParams } from '../mutations/add-hyper-link.mutation';
import { AddHyperLinkMutation } from '../mutations/add-hyper-link.mutation';
import { RemoveHyperLinkMutation } from '../mutations/remove-hyper-link.mutation';
import { HyperLinkModel } from '../../models/hyper-link.model';
import type { IAddHyperLinkMutationParams } from '@univerjs/sheets-hyper-link';
import { AddHyperLinkMutation, HyperLinkModel, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link';
export interface IRemoveHyperLinkCommandParams {
unitId: string;
subUnitId: string;
/**
* id of link
*/
id: string;
}
@@ -17,9 +17,8 @@
import type { ICommand, IMutationInfo } from '@univerjs/core';
import { CommandType, ICommandService, IUndoRedoService, sequenceExecuteAsync } from '@univerjs/core';
import { SheetInterceptorService } from '@univerjs/sheets';
import { HyperLinkModel } from '../../models/hyper-link.model';
import { UpdateHyperLinkMutation } from '../mutations/update-hyper-link.mutation';
import type { ICellHyperLink, ICellLinkContent } from '../../types/interfaces/i-hyper-link';
import type { ICellHyperLink, ICellLinkContent } from '@univerjs/sheets-hyper-link';
import { HyperLinkModel, UpdateHyperLinkMutation } from '@univerjs/sheets-hyper-link';
export interface IUpdateHyperLinkCommandParams {
unitId: string;
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import { Disposable, Inject, IPermissionService, LifecycleStages, OnLifecycle, Rectangle } from '@univerjs/core';
import { Disposable, ICommandService, Inject, IPermissionService, LifecycleStages, OnLifecycle, Rectangle } from '@univerjs/core';
import { HoverManagerService, SheetPermissionInterceptorBaseController, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
import { debounceTime } from 'rxjs';
import { IRenderManagerService } from '@univerjs/engine-render';
import { RangeProtectionPermissionEditPoint, RangeProtectionPermissionViewPoint, WorkbookCopyPermission, WorkbookEditablePermission, WorkbookViewPermission, WorksheetCopyPermission, WorksheetEditPermission, WorksheetInsertHyperlinkPermission, WorksheetViewPermission } from '@univerjs/sheets';
import { ClearSelectionAllCommand, ClearSelectionContentCommand, ClearSelectionFormatCommand, RangeProtectionPermissionEditPoint, RangeProtectionPermissionViewPoint, WorkbookCopyPermission, WorkbookEditablePermission, WorkbookViewPermission, WorksheetCopyPermission, WorksheetEditPermission, WorksheetInsertHyperlinkPermission, WorksheetViewPermission } from '@univerjs/sheets';
import { SheetsHyperLinkPopupService } from '../services/popup.service';
@OnLifecycle(LifecycleStages.Rendered, SheetsHyperLinkPopupController)
@@ -28,11 +28,13 @@ export class SheetsHyperLinkPopupController extends Disposable {
@Inject(SheetsHyperLinkPopupService) private readonly _sheetsHyperLinkPopupService: SheetsHyperLinkPopupService,
@Inject(IRenderManagerService) private readonly _renderManagerService: IRenderManagerService,
@Inject(IPermissionService) private readonly _permissionService: IPermissionService,
@Inject(SheetPermissionInterceptorBaseController) private readonly _sheetPermissionInterceptorBaseController: SheetPermissionInterceptorBaseController
@Inject(SheetPermissionInterceptorBaseController) private readonly _sheetPermissionInterceptorBaseController: SheetPermissionInterceptorBaseController,
@ICommandService private readonly _commandService: ICommandService
) {
super();
this._initHoverListener();
this._initCommandListener();
}
private _initHoverListener() {
@@ -93,4 +95,13 @@ export class SheetsHyperLinkPopupController extends Disposable {
})
);
}
private _initCommandListener() {
const HIDE_COMMAND_LIST = [ClearSelectionContentCommand.id, ClearSelectionAllCommand.id, ClearSelectionFormatCommand.id];
this.disposeWithMe(this._commandService.onCommandExecuted((command) => {
if (HIDE_COMMAND_LIST.includes(command.id)) {
this._sheetsHyperLinkPopupService.hideCurrentPopup();
}
}));
}
}
@@ -18,12 +18,15 @@ import type { IMutationInfo, Workbook } from '@univerjs/core';
import { CellValueType, CustomRangeType, Disposable, Inject, Injector, IUniverInstanceService, LifecycleStages, ObjectMatrix, OnLifecycle, Range, Tools, UniverInstanceType } from '@univerjs/core';
import type { ISetRangeValuesMutationParams } from '@univerjs/sheets';
import { ClearSelectionAllCommand, ClearSelectionContentCommand, ClearSelectionFormatCommand, getSheetCommandTarget, SetRangeValuesCommand, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory, SheetInterceptorService, SheetsSelectionsService } from '@univerjs/sheets';
import type { IAddHyperLinkCommandParams, IUpdateHyperLinkCommandParams } from '@univerjs/sheets-hyper-link';
import { AddHyperLinkCommand, AddHyperLinkMutation, HyperLinkModel, RemoveHyperLinkMutation, UpdateHyperLinkCommand } from '@univerjs/sheets-hyper-link';
import { AddHyperLinkMutation, HyperLinkModel, RemoveHyperLinkMutation } from '@univerjs/sheets-hyper-link';
import { IEditorBridgeService } from '@univerjs/sheets-ui';
import { DOC_HYPER_LINK_PLUGIN } from '@univerjs/docs-hyper-link';
import { getPlainTextFormDocument } from '@univerjs/docs';
import { isLegalLink, serializeUrl } from '../common/util';
import type { IAddHyperLinkCommandParams } from '../commands/commands/add-hyper-link.command';
import { AddHyperLinkCommand } from '../commands/commands/add-hyper-link.command';
import type { IUpdateHyperLinkCommandParams } from '../commands/commands/update-hyper-link.command';
import { UpdateHyperLinkCommand } from '../commands/commands/update-hyper-link.command';
@OnLifecycle(LifecycleStages.Starting, SheetHyperLinkSetRangeController)
export class SheetHyperLinkSetRangeController extends Disposable {
@@ -22,6 +22,9 @@ import { CellLinkPopup } from '../views/CellLinkPopup';
import { CellLinkEdit } from '../views/CellLinkEdit';
import { CloseHyperLinkSidebarOperation, InsertHyperLinkOperation, InsertHyperLinkToolbarOperation, OpenHyperLinkSidebarOperation } from '../commands/operations/sidebar.operations';
import type { IUniverSheetsHyperLinkUIConfig } from '../types/interfaces/i-config';
import { AddHyperLinkCommand } from '../commands/commands/add-hyper-link.command';
import { UpdateHyperLinkCommand } from '../commands/commands/update-hyper-link.command';
import { CancelHyperLinkCommand, RemoveHyperLinkCommand } from '../commands/commands/remove-hyper-link.command';
import { insertLinkMenuFactory, insertLinkMenuToolbarFactory, InsertLinkShortcut } from './menu';
@OnLifecycle(LifecycleStages.Ready, SheetsHyperLinkUIController)
@@ -59,6 +62,11 @@ export class SheetsHyperLinkUIController extends Disposable {
CloseHyperLinkSidebarOperation,
InsertHyperLinkOperation,
InsertHyperLinkToolbarOperation,
AddHyperLinkCommand,
UpdateHyperLinkCommand,
RemoveHyperLinkCommand,
CancelHyperLinkCommand,
].forEach((command) => {
this._commandService.registerCommand(command);
});
+3 -9
View File
@@ -14,24 +14,15 @@
* limitations under the License.
*/
export { SheetsHyperLinkRemoveSheetController } from './controllers/remove-sheet.controller';
export { SheetsHyperLinkRenderManagerController, SheetsHyperLinkRenderController } from './controllers/render-controllers/render.controller';
export { SheetsHyperLinkSidePanelService, type ICustomHyperLinkView } from './services/side-panel.service';
export { SheetsHyperLinkPopupService } from './services/popup.service';
export { SheetsHyperLinkResolverService } from './services/resolver.service';
export { SheetHyperLinkSetRangeController } from './controllers/set-range.controller';
export { SheetsHyperLinkPopupController } from './controllers/popup.controller';
export { SheetsHyperLinkUIController } from './controllers/ui.controller';
export { SheetsHyperLinkAutoFillController } from './controllers/auto-fill.controller';
export { SheetsHyperLinkCopyPasteController } from './controllers/copy-paste.controller';
export { SheetHyperLinkUrlController } from './controllers/url.controller';
export { UniverSheetsHyperLinkUIPlugin } from './plugin';
export { InsertLinkShortcut } from './controllers/menu';
export type { IUrlHandler, IUniverSheetsHyperLinkUIConfig } from './types/interfaces/i-config';
// #region - all commands
export {
OpenHyperLinkSidebarOperation,
InsertHyperLinkOperation,
@@ -39,4 +30,7 @@ export {
type IOpenHyperLinkSidebarOperationParams,
} from './commands/operations/sidebar.operations';
export { AddHyperLinkCommand, type IAddHyperLinkCommandParams } from './commands/commands/add-hyper-link.command';
export { RemoveHyperLinkCommand, CancelHyperLinkCommand, type IRemoveHyperLinkCommandParams } from './commands/commands/remove-hyper-link.command';
export { UpdateHyperLinkCommand, type IUpdateHyperLinkCommandParams } from './commands/commands/update-hyper-link.command';
// #endregion
@@ -20,7 +20,7 @@ import { createInternalEditorID, ICommandService, isValidRange, IUniverInstanceS
import type { IUnitRangeWithName, Workbook } from '@univerjs/core';
import { RangeSelector, useEvent, useObservable } from '@univerjs/ui';
import { deserializeRangeWithSheet, IDefinedNamesService, serializeRange, serializeRangeToRefString, serializeRangeWithSheet } from '@univerjs/engine-formula';
import { AddHyperLinkCommand, ERROR_RANGE, HyperLinkModel, UpdateHyperLinkCommand } from '@univerjs/sheets-hyper-link';
import { ERROR_RANGE, HyperLinkModel } from '@univerjs/sheets-hyper-link';
import { SetWorksheetActiveOperation } from '@univerjs/sheets';
import { ScrollToRangeOperation } from '@univerjs/sheets-ui';
import { SheetsHyperLinkPopupService } from '../../services/popup.service';
@@ -28,6 +28,8 @@ import { SheetsHyperLinkResolverService } from '../../services/resolver.service'
import { CloseHyperLinkSidebarOperation } from '../../commands/operations/sidebar.operations';
import { getCellValueOrigin, isLegalLink, serializeUrl } from '../../common/util';
import { LinkType, SheetsHyperLinkSidePanelService } from '../../services/side-panel.service';
import { AddHyperLinkCommand } from '../../commands/commands/add-hyper-link.command';
import { UpdateHyperLinkCommand } from '../../commands/commands/update-hyper-link.command';
import styles from './index.module.less';
export const CellLinkEdit = () => {
@@ -15,7 +15,7 @@
*/
import { ICommandService, LocaleService, useDependency } from '@univerjs/core';
import { CancelHyperLinkCommand, HyperLinkModel } from '@univerjs/sheets-hyper-link';
import { HyperLinkModel } from '@univerjs/sheets-hyper-link';
import React, { useEffect, useState } from 'react';
import { AllBorderSingle, CopySingle, LinkSingle, UnlinkSingle, WriteSingle, Xlsx } from '@univerjs/icons';
import cs from 'clsx';
@@ -25,6 +25,7 @@ import type { IHyperLinkPopup } from '../../services/popup.service';
import { SheetsHyperLinkPopupService } from '../../services/popup.service';
import { SheetsHyperLinkResolverService } from '../../services/resolver.service';
import { OpenHyperLinkSidebarOperation } from '../../commands/operations/sidebar.operations';
import { CancelHyperLinkCommand } from '../../commands/commands/remove-hyper-link.command';
import styles from './index.module.less';
const iconsMap = {
@@ -18,9 +18,6 @@ import { Disposable, ICommandService, LifecycleStages, OnLifecycle } from '@univ
import { AddHyperLinkMutation } from '../commands/mutations/add-hyper-link.mutation';
import { UpdateHyperLinkMutation, UpdateHyperLinkRefMutation } from '../commands/mutations/update-hyper-link.mutation';
import { RemoveHyperLinkMutation } from '../commands/mutations/remove-hyper-link.mutation';
import { AddHyperLinkCommand } from '../commands/commands/add-hyper-link.command';
import { UpdateHyperLinkCommand } from '../commands/commands/update-hyper-link.command';
import { CancelHyperLinkCommand, RemoveHyperLinkCommand } from '../commands/commands/remove-hyper-link.command';
@OnLifecycle(LifecycleStages.Starting, SheetsHyperLinkController)
export class SheetsHyperLinkController extends Disposable {
@@ -38,11 +35,6 @@ export class SheetsHyperLinkController extends Disposable {
UpdateHyperLinkMutation,
RemoveHyperLinkMutation,
UpdateHyperLinkRefMutation,
AddHyperLinkCommand,
UpdateHyperLinkCommand,
RemoveHyperLinkCommand,
CancelHyperLinkCommand,
].forEach((command) => {
this._commandService.registerCommand(command);
});
-5
View File
@@ -15,19 +15,14 @@
*/
export { HyperLinkModel } from './models/hyper-link.model';
export { SheetsHyperLinkController } from './controllers/sheet-hyper-link.controller';
export { HyperLinkType } from './types/enums/hyper-link-type';
export { UniverSheetsHyperLinkPlugin } from './plugin';
export { SheetsHyperLinkRefRangeController } from './controllers/ref-range.controller';
export type { ICellHyperLink, ICellLinkContent } from './types/interfaces/i-hyper-link';
export { ERROR_RANGE } from './types/const';
// #region - all commands
export { AddHyperLinkCommand, type IAddHyperLinkCommandParams } from './commands/commands/add-hyper-link.command';
export { RemoveHyperLinkCommand, CancelHyperLinkCommand, type IRemoveHyperLinkCommandParams } from './commands/commands/remove-hyper-link.command';
export { UpdateHyperLinkCommand, type IUpdateHyperLinkCommandParams } from './commands/commands/update-hyper-link.command';
export { AddHyperLinkMutation, type IAddHyperLinkMutationParams } from './commands/mutations/add-hyper-link.mutation';
export { RemoveHyperLinkMutation, type IRemoveHyperLinkMutationParams } from './commands/mutations/remove-hyper-link.mutation';
export { UpdateHyperLinkMutation, UpdateHyperLinkRefMutation, type IUpdateHyperLinkMutationParams, type IUpdateHyperLinkRefMutationParams } from './commands/mutations/update-hyper-link.mutation';
@@ -30,7 +30,16 @@ export interface ICellLinkContent {
}
export interface ICellHyperLink extends ICellLinkContent {
/**
* unique id
*/
id: string;
/**
* row of link
*/
row: number;
/**
* col of link
*/
column: number;
}
@@ -53,6 +53,7 @@ export class SheetsNumfmtCellContentController extends Disposable {
this._initInterceptorCellContent();
}
// eslint-disable-next-line max-lines-per-function
private _initInterceptorCellContent() {
const renderCache = new ObjectMatrix<{ result: ICellData; parameters: string | number }>();
this.disposeWithMe(this._sheetInterceptorService.intercept(INTERCEPTOR_POINT.CELL_CONTENT, {
@@ -60,12 +61,14 @@ export class SheetsNumfmtCellContentController extends Disposable {
const unitId = location.unitId;
const sheetId = location.subUnitId;
let numfmtValue;
if (cell?.s) {
const style = location.workbook.getStyles().get(cell.s);
if (style?.n) {
numfmtValue = style.n;
}
}
if (!numfmtValue) {
numfmtValue = this._numfmtService.getValue(unitId, sheetId, location.row, location.col);
}
+29
View File
@@ -62,6 +62,35 @@ univer.registerPlugin(UniverSheetsThreadCommentPlugin, {
});
```
### API
```typescript
import {
AddCommentCommand,
DeleteCommentCommand,
UpdateCommentCommand,
ResolveCommentCommand,
DeleteCommentTreeCommand,
} from '@univerjs/sheets-thread-comment';
import type {
IAddCommentCommandParams,
IDeleteCommentCommandParams,
IResolveCommentCommandParams,
IUpdateCommentCommandParams,
IDeleteCommentTreeCommandParams,
} from '@univerjs/sheets-thread-comment';
// Add comment by command
const commandService = univer.__getInjector().get(ICommandService);
commandService.executeCommand(AddCommentCommand.id, {
unitId: 'unitId',
subUnitId: 'subUnitId',
comment: {
// comment content
},
} as IAddCommentCommandParams);
```
<!-- Links -->
[npm-version-shield]: https://img.shields.io/npm/v/@univerjs/sheets-thread-comment?style=flat-square
[npm-version-link]: https://npmjs.com/package/@univerjs/sheets-thread-comment
+14 -4
View File
@@ -18,13 +18,9 @@ export type { Dependency } from '@univerjs/core';
export { Inject, Injector } from '@univerjs/core';
export { ICommandService, Plugin, UniverInstanceType } from '@univerjs/core';
export { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui';
export { SheetsThreadCommentController } from './controllers/sheets-thread-comment.controller';
export { SheetsThreadCommentPopupService } from './services/sheets-thread-comment-popup.service';
export { UniverSheetsThreadCommentPlugin } from './plugin';
export { SHEETS_THREAD_COMMENT } from './types/const';
export { SheetsThreadCommentCopyPasteController } from './controllers/sheets-thread-comment-copy-paste.controller';
export { SheetsThreadCommentHoverController } from './controllers/sheets-thread-comment-hover.controller';
export { ThreadCommentRemoveSheetsController } from './controllers/sheets-thread-comment-remove.controller';
export { IThreadCommentMentionDataService } from '@univerjs/thread-comment-ui';
export { IThreadCommentDataSourceService } from '@univerjs/thread-comment';
export { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base';
@@ -32,5 +28,19 @@ export { SheetsThreadCommentModel } from '@univerjs/sheets-thread-comment-base';
// #region - all commands
export { ShowAddSheetCommentModalOperation } from './commands/operations/comment.operation';
export {
AddCommentCommand,
DeleteCommentCommand,
UpdateCommentCommand,
ResolveCommentCommand,
DeleteCommentTreeCommand,
} from '@univerjs/thread-comment';
export type {
IAddCommentCommandParams,
IDeleteCommentCommandParams,
IResolveCommentCommandParams,
IUpdateCommentCommandParams,
IDeleteCommentTreeCommandParams,
} from '@univerjs/thread-comment';
// #endregion
@@ -73,7 +73,9 @@ export class SheetsThreadCommentPopupService extends Disposable {
this._activePopup$.next(location);
return;
}
this._lastPopup && this._lastPopup.dispose();
if (this._lastPopup) {
this._lastPopup.dispose();
};
if (this._zenZoneService.visible) {
return;
}
@@ -116,7 +118,9 @@ export class SheetsThreadCommentPopupService extends Disposable {
if (!this._activePopup) {
return;
}
this._lastPopup && this._lastPopup.dispose();
if (this._lastPopup) {
this._lastPopup.dispose();
}
this._lastPopup = null;
this._activePopup = null;
@@ -353,6 +353,7 @@ export function getSetCellStyleMutations(
...DEFAULT_STYLES,
pd: DEFAULT_PADDING_DATA,
bg: null,
cl: null,
}, value.s),
};
if (withRichFormat && value.p?.body) {
@@ -29,9 +29,7 @@ import { SetZoomRatioOperation } from '../commands/operations/set-zoom-ratio.ope
import { SheetSkeletonManagerService } from './sheet-skeleton-manager.service';
import { ISheetSelectionRenderService } from './selection/base-selection-render.service';
export interface ICanvasPopup extends Pick<IPopup,
'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside'
> {
export interface ICanvasPopup extends Pick<IPopup, 'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside' | 'hideOnInvisible'> {
mask?: boolean;
extraProps?: Record<string, any>;
}
@@ -134,6 +132,7 @@ export class SheetCanvasPopManagerService extends Disposable {
subUnitId,
anchorRect: position,
anchorRect$: position$,
canvasElement: currentRender.engine.getCanvasElement(),
});
return {
@@ -193,6 +192,7 @@ export class SheetCanvasPopManagerService extends Disposable {
subUnitId,
anchorRect: position,
anchorRect$: position$,
canvasElement: currentRender.engine.getCanvasElement(),
});
const disposableCollection = new DisposableCollection();
@@ -61,7 +61,9 @@ export class CellAlertManagerService extends Disposable {
showAlert(alert: ICellAlert) {
let lastPopup = this._currentAlert.get(alert.key);
lastPopup && lastPopup.dispose.dispose();
if (lastPopup) {
lastPopup.dispose.dispose();
};
if (lastPopup) {
lastPopup.dispose.dispose();
} else {
@@ -151,17 +151,17 @@ describe('Test clipboard', () => {
expect(getValues(2, 2, 2, 2)?.[0]?.[0]?.v).toEqual('Univer');
expect(getStyles(2, 2, 2, 2)?.[0]?.[0]).toStrictEqual({
bl: 1,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 0,
it: 1,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -171,9 +171,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -183,9 +183,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 3,
@@ -164,17 +164,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -184,9 +184,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -196,9 +196,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -237,17 +237,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -257,9 +257,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -269,9 +269,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -310,17 +310,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -330,9 +330,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -342,9 +342,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -387,17 +387,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -407,9 +407,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -419,9 +419,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -431,17 +431,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -451,9 +451,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -463,9 +463,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -515,17 +515,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -535,9 +535,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -547,9 +547,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -559,17 +559,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -579,9 +579,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -591,9 +591,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -681,17 +681,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -701,9 +701,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -713,9 +713,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -819,17 +819,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -839,9 +839,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -851,9 +851,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -946,17 +946,17 @@ describe('Test clipboard', () => {
rgb: 'rgb(255,0,0)',
},
bl: 0,
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
ff: 'Arial',
fs: 10,
ht: 2,
it: 0,
ol: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
pd: {
@@ -966,9 +966,9 @@ describe('Test clipboard', () => {
t: 0,
},
st: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
tb: 0,
@@ -978,9 +978,9 @@ describe('Test clipboard', () => {
v: 0,
},
ul: {
cl: {
rgb: '#000',
},
// cl: {
// rgb: '#000',
// },
s: 0,
},
vt: 2,
@@ -24,7 +24,7 @@ import { ICanvasPopupService } from '@univerjs/ui';
import { BehaviorSubject } from 'rxjs';
export interface ISlideCanvasPopup extends Pick<IPopup,
'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside'
'direction' | 'excludeOutside' | 'closeOnSelfTarget' | 'componentKey' | 'offset' | 'onClickOutside' | 'hideOnInvisible'
> {
mask?: boolean;
extraProps?: Record<string, any>;
@@ -156,6 +156,7 @@ export class SlideCanvasPopMangerService extends Disposable {
subUnitId: 'default',
anchorRect: position,
anchorRect$: position$,
canvasElement: currentRender.engine.getCanvasElement(),
});
return {
@@ -31,6 +31,8 @@ export interface IPopup extends Pick<IRectPopupProps, 'closeOnSelfTarget' | 'dir
subUnitId: string;
offset?: [number, number];
canvasElement: HTMLCanvasElement;
hideOnInvisible?: boolean;
}
export interface ICanvasPopupService {
@@ -15,19 +15,28 @@
*/
import { useDependency } from '@univerjs/core';
import React, { useMemo } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { RectPopup } from '@univerjs/design';
import type { IBoundRectNoAngle } from '@univerjs/engine-render';
import { throttleTime } from 'rxjs';
import { ICanvasPopupService } from '../../../services/popup/canvas-popup.service';
import { useObservable } from '../../../components/hooks/observable';
import { ComponentManager } from '../../../common';
import type { IPopup } from '../../../services/popup/canvas-popup.service';
const SingleCanvasPopup = ({ popup, children }: { popup: IPopup; children?: React.ReactNode }) => {
const anchorRect = useObservable(popup.anchorRect$, popup.anchorRect);
const excludeRects = useObservable(popup.excludeRects$, popup.excludeRects);
interface ISingleCanvasPopupProps {
popup: IPopup;
children?: React.ReactNode;
}
const SingleCanvasPopup = ({ popup, children }: ISingleCanvasPopupProps) => {
const [hidden, setHidden] = useState(false);
const anchorRect$ = useMemo(() => popup.anchorRect$.pipe(throttleTime(16)), [popup.anchorRect$]);
const excludeRects$ = useMemo(() => popup.excludeRects$?.pipe(throttleTime(16)), [popup.excludeRects$]);
const anchorRect = useObservable(anchorRect$, popup.anchorRect);
const excludeRects = useObservable(excludeRects$, popup.excludeRects);
const { bottom, left, right, top } = anchorRect;
const { offset } = popup;
const { offset, canvasElement, hideOnInvisible = true } = popup;
// We add an offset to the anchor rect to make the popup offset with the anchor.
const rectWithOffset: IBoundRectNoAngle = useMemo(() => {
@@ -40,6 +49,23 @@ const SingleCanvasPopup = ({ popup, children }: { popup: IPopup; children?: Reac
};
}, [bottom, left, right, top, offset]);
useEffect(() => {
if (!hideOnInvisible) {
return;
}
const rect = canvasElement.getBoundingClientRect();
const { top, left, bottom, right } = rect;
if (rectWithOffset.bottom < top || rectWithOffset.top > bottom || rectWithOffset.right < left || rectWithOffset.left > right) {
setHidden(true);
} else {
setHidden(false);
}
}, [rectWithOffset, canvasElement, hideOnInvisible]);
if (hidden) {
return null;
}
return (
<RectPopup
anchorRect={rectWithOffset}