Skip to content

Commit

Permalink
feat(sheets-data-validation): support dropdown filter & fix paste err…
Browse files Browse the repository at this point in the history
…or on data-validation cell (#3057)
  • Loading branch information
weird94 authored Aug 16, 2024
1 parent dc566fd commit e2e7d2a
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 67 deletions.
5 changes: 3 additions & 2 deletions examples/src/data/sheets/demo/default-workbook-data-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import type { IDocumentData, IWorkbookData } from '@univerjs/core';
import type { IDataValidationRule, IDocumentData, IWorkbookData } from '@univerjs/core';
import { BooleanNumber, DataValidationErrorStyle, DataValidationOperator, DataValidationType, LocaleType } from '@univerjs/core';

import { DATA_VALIDATION_PLUGIN_NAME } from '@univerjs/sheets-data-validation';
Expand Down Expand Up @@ -102,7 +102,7 @@ const richTextDemo1: IDocumentData = {
},
};

const dataValidation = [
const dataValidation: IDataValidationRule[] = [
{
uid: 'xxx-1',
type: DataValidationType.DECIMAL,
Expand Down Expand Up @@ -150,6 +150,7 @@ const dataValidation = [
endColumn: 5,
}],
formula1: '1,2,3,hahaha,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18',
renderMode: 1,
},
{
uid: 'xxx-4',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types/const/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export const DEFAULT_STYLES = {
b: 0,
l: 0,
},
n: null,
};

export const DEFAULT_SLIDE = {
Expand Down
2 changes: 2 additions & 0 deletions packages/sheets-data-validation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@univerjs/core": "workspace:*",
"@univerjs/data-validation": "workspace:*",
"@univerjs/design": "workspace:*",
"@univerjs/docs": "workspace:*",
"@univerjs/engine-formula": "workspace:*",
"@univerjs/engine-render": "workspace:*",
"@univerjs/sheets": "workspace:*",
Expand All @@ -84,6 +85,7 @@
"@univerjs/core": "workspace:*",
"@univerjs/data-validation": "workspace:*",
"@univerjs/design": "workspace:*",
"@univerjs/docs": "workspace:*",
"@univerjs/engine-formula": "workspace:*",
"@univerjs/engine-render": "workspace:*",
"@univerjs/shared": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ export class SheetsDataValidationMobileRenderController extends RxDisposable {
INTERCEPTOR_POINT.CELL_CONTENT,
{
priority: 200,
// eslint-disable-next-line max-lines-per-function
// eslint-disable-next-line max-lines-per-function, complexity
handler: (cell, pos, next) => {
const { row, col, unitId, subUnitId, workbook, worksheet } = pos;
const manager = this._dataValidationModel.ensureManager(unitId, subUnitId) as SheetDataValidationManager;
Expand Down
19 changes: 6 additions & 13 deletions packages/sheets-data-validation/src/validators/date-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { getFormulaResult } from '../utils/formula';
import { DATE_DROPDOWN_KEY } from '../views';
import { DateOperatorErrorTitleMap, DateOperatorNameMap, DateOperatorTitleMap } from '../common/date-text-map';
import { DateShowTimeOption } from '../views/show-time';
import { getCellValueOrigin } from '../utils/get-cell-data-origin';

const FORMULA1 = '{FORMULA1}';
const FORMULA2 = '{FORMULA2}';
Expand Down Expand Up @@ -87,19 +88,11 @@ export class DateValidator extends BaseDataValidator<number> {
}

override async isValidType(info: IValidatorCellInfo): Promise<boolean> {
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') {
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;
}
}
const { value, worksheet, row, column } = info;
const cell = worksheet.getCell(row, column);
const interceptValue = getCellValueOrigin(cell);
if (typeof interceptValue === 'string' && typeof value === 'number') {
return dayjs(interceptValue).isValid();
}

return false;
Expand Down
67 changes: 55 additions & 12 deletions packages/sheets-data-validation/src/views/list-dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@
* limitations under the License.
*/

import { DataValidationRenderMode, DataValidationType, ICommandService, LocaleService, useDependency } from '@univerjs/core';
import type { DocumentDataModel } from '@univerjs/core';
import { DataValidationRenderMode, DataValidationType, ICommandService, IUniverInstanceService, LocaleService, UniverInstanceType, useDependency } from '@univerjs/core';
import type { ISetRangeValuesCommandParams } from '@univerjs/sheets';
import { SetRangeValuesCommand } from '@univerjs/sheets';
import React, { useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { CheckMarkSingle } from '@univerjs/icons';
import { IEditorBridgeService } from '@univerjs/sheets-ui';
import { KeyCode, useObservable } from '@univerjs/ui';
import { DeviceInputEventType } from '@univerjs/engine-render';
import { RectPopup, Scrollbar } from '@univerjs/design';
import { DataValidationModel } from '@univerjs/data-validation';
import { debounceTime } from 'rxjs';
import type { IRichTextEditingMutationParams } from '@univerjs/docs';
import { getPlainTextFormDocument, RichTextEditingMutation } from '@univerjs/docs';
import type { ListMultipleValidator } from '../../validators/list-multiple-validator';
import { deserializeListOptions, getDataValidationCellValue, serializeListOptions } from '../../validators/util';
import type { IDropdownComponentProps } from '../../services/dropdown-manager.service';
Expand All @@ -40,21 +43,24 @@ interface ISelectListProps {
title?: string;
onEdit?: () => void;
style?: React.CSSProperties;
filter?: string;
}

const SelectList = (props: ISelectListProps) => {
const { value, onChange, multiple, options, title, onEdit, style } = props;
const { value, onChange, multiple, options, title, onEdit, style, filter } = props;
const localeService = useDependency(LocaleService);
const lowerFilter = filter?.toLowerCase();
const filteredOptions = options.filter((item) => lowerFilter ? item.label.toLowerCase().includes(lowerFilter) : true);

return (
<div className={styles.dvListDropdown} style={style}>
<div className={styles.dvListDropdownTitle}>
{title}
</div>
<div className={styles.dvListDropdownList}>
<Scrollbar>
<Scrollbar key={filter}>
<div className={styles.dvListDropdownListContainer}>
{options.map((item, i) => {
{filteredOptions.map((item, i) => {
const selected = value.indexOf(item.value) > -1;
const handleClick = () => {
let set: Set<string>;
Expand All @@ -72,9 +78,21 @@ const SelectList = (props: ISelectListProps) => {

onChange(newValue);
};

const index = item.label.toLocaleLowerCase().indexOf(lowerFilter!);
return (
<div key={i} className={styles.dvListDropdownItemContainer} onClick={handleClick}>
<div className={styles.dvListDropdownItem} style={{ background: item.color || DROP_DOWN_DEFAULT_COLOR }}>{item.label}</div>
<div className={styles.dvListDropdownItem} style={{ background: item.color || DROP_DOWN_DEFAULT_COLOR }}>
{lowerFilter && item.label.toLowerCase().includes(lowerFilter)
? (
<>
<span>{item.label.substring(0, index)}</span>
<span style={{ fontWeight: 'bold' }}>{item.label.substring(index, index + lowerFilter.length)}</span>
<span>{item.label.substring(index + lowerFilter.length)}</span>
</>
)
: item.label}
</div>
<div className={styles.dvListDropdownSelectedIcon}>
{selected ? <CheckMarkSingle /> : null}
</div>
Expand All @@ -96,14 +114,36 @@ export function ListDropDown(props: IDropdownComponentProps) {
const { location, hideFn } = props;
const { worksheet, row, col, unitId, subUnitId } = location;
const dataValidationModel = useDependency(DataValidationModel);
const [editingText, setEditingText] = useState('');
const commandService = useDependency(ICommandService);
const localeService = useDependency(LocaleService);
const [localValue, setLocalValue] = useState('');
const editorBridgeService = useDependency(IEditorBridgeService);
const instanceService = useDependency(IUniverInstanceService);
const ruleChange$ = useMemo(() => dataValidationModel.ruleChange$.pipe(debounceTime(16)), []);
useObservable(ruleChange$);
const anchorRect = RectPopup.useContext();
const cellWidth = anchorRect.right - anchorRect.left;

useEffect(() => {
const dispose = commandService.onCommandExecuted((command) => {
if (command.id === RichTextEditingMutation.id) {
const params = command.params as IRichTextEditingMutationParams;
const { unitId } = params;
const unit = instanceService.getUnit<DocumentDataModel>(unitId, UniverInstanceType.UNIVER_DOC);
if (!unit) {
return;
}
const text = getPlainTextFormDocument(unit.getSnapshot());
setEditingText(text);
}
});

return () => {
dispose.dispose();
};
}, [commandService, instanceService]);

if (!worksheet) {
return null;
}
Expand All @@ -113,7 +153,7 @@ export function ListDropDown(props: IDropdownComponentProps) {
const validator = cellData?.dataValidation?.validator as ListMultipleValidator | undefined;
const showColor = rule?.renderMode === DataValidationRenderMode.CUSTOM || rule?.renderMode === undefined;

if (!cellData || !rule || !validator) {
if (!cellData || !rule || !validator || validator.id.indexOf(DataValidationType.LIST) !== 0) {
return;
}

Expand All @@ -129,6 +169,12 @@ export function ListDropDown(props: IDropdownComponentProps) {
hideFn();
};

const options = list.map((item) => ({
label: item.label,
value: item.label,
color: showColor ? item.color : 'transparent',
}));

return (
<SelectList
style={{ minWidth: cellWidth, maxWidth: Math.max(cellWidth, 200) }}
Expand Down Expand Up @@ -172,12 +218,9 @@ export function ListDropDown(props: IDropdownComponentProps) {
hideFn();
}
}}
options={list.map((item) => ({
label: item.label,
value: item.label,
color: showColor ? item.color : 'transparent',
}))}
options={options}
onEdit={handleEdit}
filter={editingText}
/>
);
}
Loading

0 comments on commit e2e7d2a

Please sign in to comment.