refactor(sheets-conditional-formatting): migrate styles from LESS to Tailwind CSS (#5133)

Co-authored-by: GitHub Actions <actions@github.com>
This commit is contained in:
白熱
2025-04-30 21:25:36 +08:00
committed by GitHub
co-authored by GitHub Actions
parent 5afa3ef002
commit ee12da274e
104 changed files with 991 additions and 2399 deletions
+3 -3
View File
@@ -24,7 +24,7 @@
"univer-cli": "bin/index.ts"
},
"dependencies": {
"@typescript-eslint/parser": "^8.31.0",
"@typescript-eslint/parser": "^8.31.1",
"@vitejs/plugin-react": "^4.4.1",
"@vitejs/plugin-vue": "^5.2.3",
"@vitest/coverage-istanbul": "^3.1.2",
@@ -38,7 +38,7 @@
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.17",
"tailwindcss-rem-to-px": "^0.1.1",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vite-plugin-dts": "^4.5.3",
"vite-plugin-external": "^6.2.1",
"vitest": "^3.1.2"
@@ -46,7 +46,7 @@
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@univerjs/icons": "^0.3.24",
"@univerjs/icons-svg": "^0.3.22",
"@univerjs/icons-svg": "^0.3.24",
"@univerjs/protocol": "0.1.45"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

+1 -2
View File
@@ -27,7 +27,6 @@
"@univerjs/docs-drawing-ui": "workspace:*",
"@univerjs/docs-hyper-link-ui": "workspace:*",
"@univerjs/docs-mention-ui": "workspace:*",
"@univerjs/docs-quick-insert-ui": "workspace:*",
"@univerjs/docs-thread-comment-ui": "workspace:*",
"@univerjs/docs-ui": "workspace:*",
@@ -36,7 +35,7 @@
"@univerjs/engine-formula": "workspace:*",
"@univerjs/engine-render": "workspace:*",
"@univerjs/find-replace": "workspace:*",
"@univerjs/icons": "0.3.23",
"@univerjs/icons": "0.3.24",
"@univerjs/mockdata": "workspace:*",
"@univerjs/network": "workspace:*",
"@univerjs/rpc": "workspace:*",
+2 -2
View File
@@ -56,7 +56,7 @@
"@types/fs-extra": "^11.0.4",
"@types/node": "^22.15.3",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@types/react-dom": "^19.1.3",
"@univerjs-infra/shared": "workspace:*",
"@univerjs/design": "workspace:*",
"@vitejs/plugin-react": "^4.4.1",
@@ -72,7 +72,7 @@
"fs-extra": "^11.3.0",
"husky": "^9.1.7",
"lint-staged": "^15.5.1",
"posthog-node": "^4.14.0",
"posthog-node": "^4.15.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"release-it": "^17.11.0",
@@ -80,7 +80,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -85,7 +85,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2",
"vue": "^3.5.13"
}
@@ -77,7 +77,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -73,7 +73,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -85,7 +85,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -61,7 +61,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -78,7 +78,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -74,7 +74,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -79,7 +79,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -94,7 +94,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -70,7 +70,7 @@
"@univerjs/sheets": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -102,7 +102,7 @@
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -85,7 +85,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -62,7 +62,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -82,7 +82,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -61,7 +61,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -75,7 +75,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -85,7 +85,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -76,7 +76,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -97,7 +97,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -24,7 +24,7 @@ interface ICountBarProps {
export function CountBar(_props: ICountBarProps) {
return (
<section className="univer-flex univer-flex-shrink-0 univer-flex-grow-0 univer-basis-[260px] univer-justify-end">
<section className="univer-flex univer-flex-shrink-0 univer-justify-end">
<ZoomSlider />
</section>
);
+1 -1
View File
@@ -68,7 +68,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -81,7 +81,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -66,7 +66,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -83,7 +83,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -60,7 +60,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -73,7 +73,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
},
"browser": {
+1 -1
View File
@@ -81,7 +81,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -77,7 +77,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -66,7 +66,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -66,7 +66,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -85,13 +85,12 @@
"devDependencies": {
"@types/react-grid-layout": "^1.3.5",
"@univerjs-infra/shared": "workspace:*",
"less": "^4.3.0",
"postcss": "^8.5.3",
"react": "18.3.1",
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -1,18 +0,0 @@
.cf-style-edit {
display: flex;
justify-content: space-between;
margin: 10px 0px;
.button-item {
cursor: pointer;
border-radius: var(--border-radius-base);
display: flex;
align-items: center;
padding: 0px 3px;
&:hover {
background-color: rgb(var(--grey-100));
}
}
.isActive {
background-color: rgb(var(--grey-100));
}
}
@@ -21,7 +21,6 @@ import { removeUndefinedAttr } from '@univerjs/sheets-conditional-formatting';
import { ComponentManager, useDependency } from '@univerjs/ui';
import { useEffect, useState } from 'react';
import { ColorPicker } from '../color-picker';
import styles from './index.module.less';
interface IConditionalStyleEditorProps {
className?: string;
@@ -101,13 +100,16 @@ export const ConditionalStyleEditor = (props: IConditionalStyleEditorProps) => {
}
onChange(removeUndefinedAttr(resultStyle));
}, [isBold, isItalic, isUnderline, isStrikethrough, fontColor, bgColor]);
const buttonItemClassName = 'univer-flex univer-cursor-pointer univer-items-center univer-rounded univer-px-1';
return (
<div
className={clsx(styles.cfStyleEdit, className)}
>
<div className={clsx('univer-my-2.5 univer-flex univer-justify-between', className)}>
{BoldSingleIcon && (
<div
className={clsx({ [styles.isActive]: getBooleanFromNumber(isBold || BooleanNumber.FALSE) }, styles.buttonItem)}
className={clsx(buttonItemClassName, {
'univer-bg-gray-100': getBooleanFromNumber(isBold || BooleanNumber.FALSE),
})}
onClick={() => isBoldSet(getAnotherBooleanNumber(isBold))}
>
<BoldSingleIcon />
@@ -115,7 +117,9 @@ export const ConditionalStyleEditor = (props: IConditionalStyleEditorProps) => {
)}
{ItalicSingleIcon && (
<div
className={clsx({ [styles.isActive]: getBooleanFromNumber(isItalic || BooleanNumber.FALSE) }, styles.buttonItem)}
className={clsx(buttonItemClassName, {
'univer-bg-gray-100': getBooleanFromNumber(isItalic || BooleanNumber.FALSE),
})}
onClick={() => isItalicSet(getAnotherBooleanNumber(isItalic))}
>
<ItalicSingleIcon />
@@ -123,7 +127,9 @@ export const ConditionalStyleEditor = (props: IConditionalStyleEditorProps) => {
)}
{UnderlineSingleIcon && (
<div
className={clsx({ [styles.isActive]: getBooleanFromNumber(isUnderline || BooleanNumber.FALSE) }, styles.buttonItem)}
className={clsx(buttonItemClassName, {
'univer-bg-gray-100': getBooleanFromNumber(isUnderline || BooleanNumber.FALSE),
})}
onClick={() => isUnderlineSet(getAnotherBooleanNumber(isUnderline))}
>
<UnderlineSingleIcon />
@@ -131,7 +137,9 @@ export const ConditionalStyleEditor = (props: IConditionalStyleEditorProps) => {
)}
{StrikethroughSingle && (
<div
className={clsx({ [styles.isActive]: getBooleanFromNumber(isStrikethrough || BooleanNumber.FALSE) }, styles.buttonItem)}
className={clsx(buttonItemClassName, {
'univer-bg-gray-100': getBooleanFromNumber(isStrikethrough || BooleanNumber.FALSE),
})}
onClick={() => isStrikethroughSet(getAnotherBooleanNumber(isStrikethrough))}
>
<StrikethroughSingle />
@@ -1,45 +0,0 @@
.conditional-formatting-wrap {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.cf-rule-item {
display: flex;
justify-content: space-between;
align-items: center;
.preview {
flex-shrink: 0;
}
}
.create-rule {
margin-bottom: 20px;
.button {
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-base);
display: flex;
align-items: center;
justify-content: center;
padding: var(--padding-base);
cursor: pointer;
font-size: var(--font-size-sm);
}
}
.title {
margin-top: var(--margin-base);
font-size: 15px;
color: rgb(var(--text-color-secondary));
}
.label {
font-size: 12px;
margin-top: var(--margin-sm);
color: rgb(var(--text-color-secondary));
}
.label-container {
display: flex;
align-items: center;
.input-width {
width: 100px;
}
}
}
@@ -14,11 +14,10 @@
* limitations under the License.
*/
import React, { useState } from 'react';
import type { IConditionFormattingRule } from '@univerjs/sheets-conditional-formatting';
import styles from './index.module.less';
import { RuleList } from './rule-list';
import { useState } from 'react';
import { RuleEdit } from './rule-edit';
import { RuleList } from './rule-list';
interface IConditionFormattingPanelProps { rule?: IConditionFormattingRule };
@@ -41,7 +40,7 @@ export const ConditionFormattingPanel = (props: IConditionFormattingPanelProps)
};
return (
<div className={styles.conditionalFormattingWrap}>
<div className="univer-flex univer-h-full univer-flex-col univer-justify-between">
{isShowRuleEditor
? (
<RuleEdit onCancel={handleCancel} rule={currentEditRule} />
@@ -19,15 +19,14 @@ import type { IColorScale, IConditionalFormattingRuleConfig } from '@univerjs/sh
import type { IFormulaEditorRef } from '@univerjs/sheets-formula-ui';
import type { IStyleEditorProps } from './type';
import { IUniverInstanceService, LocaleService, UniverInstanceType } from '@univerjs/core';
import { clsx, InputNumber, Select } from '@univerjs/design';
import { InputNumber, Select } from '@univerjs/design';
import { CFRuleType, CFValueType, createDefaultValueByValueType } from '@univerjs/sheets-conditional-formatting';
import { FormulaEditor } from '@univerjs/sheets-formula-ui';
import { useDependency, useSidebarClick } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
import { ColorPicker } from '../../color-picker';
import { Preview } from '../../preview';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
import { previewClassName } from './styles';
const createOptionItem = (text: string, localeService: LocaleService) => ({ label: localeService.t(`sheet.cf.valueType.${text}`), value: text });
@@ -57,16 +56,16 @@ const TextInput = (props: { id: string; type: CFValueType | 'none'; value: numbe
}, [type]);
const formulaEditorRef = useRef<IFormulaEditorRef>(null);
const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false);
const [isFocusFormulaEditor, setIsFocusFormulaEditor] = useState(false);
useSidebarClick((e: MouseEvent) => {
const isOutSide = formulaEditorRef.current?.isClickOutSide(e);
isOutSide && isFocusFormulaEditorSet(false);
isOutSide && setIsFocusFormulaEditor(false);
});
if (type === CFValueType.formula) {
return (
<div style={{ width: '100%', marginLeft: 4 }}>
<div className="univer-ml-1 univer-w-full">
<FormulaEditor
initValue={formulaInitValue as any}
unitId={unitId}
@@ -76,7 +75,7 @@ const TextInput = (props: { id: string; type: CFValueType | 'none'; value: numbe
const formula = v || '';
onChange(formula);
}}
onFocus={() => isFocusFormulaEditorSet(true)}
onFocus={() => setIsFocusFormulaEditor(true)}
ref={formulaEditorRef}
/>
</div>
@@ -95,14 +94,14 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
const medianOptions = [createOptionItem('none', localeService), ...commonOptions];
const maxOptions = [createOptionItem(CFValueType.max, localeService), ...commonOptions];
const [minType, minTypeSet] = useState(() => {
const [minType, setMinType] = useState(() => {
const defaultV = CFValueType.min;
if (!rule) {
return defaultV;
}
return rule.config[0]?.value.type || defaultV;
});
const [medianType, medianTypeSet] = useState<CFValueType | 'none'>(() => {
const [medianType, setMedianType] = useState<CFValueType | 'none'>(() => {
const defaultV = 'none';
if (!rule) {
return defaultV;
@@ -112,7 +111,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
}
return rule.config[1]?.value.type || defaultV;
});
const [maxType, maxTypeSet] = useState(() => {
const [maxType, setMaxType] = useState(() => {
const defaultV = CFValueType.max;
if (!rule) {
return defaultV;
@@ -120,7 +119,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
return rule.config[rule.config.length - 1]?.value.type || defaultV;
});
const [minValue, minValueSet] = useState(() => {
const [minValue, setMinValue] = useState(() => {
const defaultV = 10;
if (!rule) {
return defaultV;
@@ -128,7 +127,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
const valueConfig = rule.config[0];
return valueConfig?.value.value === undefined ? defaultV : valueConfig?.value.value;
});
const [medianValue, medianValueSet] = useState(() => {
const [medianValue, setMedianValue] = useState(() => {
const defaultV = 50;
if (!rule) {
return defaultV;
@@ -139,7 +138,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
const v = rule.config[1]?.value.value;
return v === undefined ? defaultV : v;
});
const [maxValue, maxValueSet] = useState(() => {
const [maxValue, setMaxValue] = useState(() => {
const defaultV = 90;
if (!rule) {
return defaultV;
@@ -148,14 +147,14 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
return v === undefined ? defaultV : v;
});
const [minColor, minColorSet] = useState(() => {
const [minColor, setMinColor] = useState(() => {
const defaultV = '#d0d9fb';
if (!rule) {
return defaultV;
}
return rule.config[0]?.color || defaultV;
});
const [medianColor, medianColorSet] = useState(() => {
const [medianColor, setMedianColor] = useState(() => {
const defaultV = '#7790f3';
if (!rule) {
return defaultV;
@@ -165,7 +164,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
}
return rule.config[1]?.color || defaultV;
});
const [maxColor, maxColorSet] = useState(() => {
const [maxColor, setMaxColor] = useState(() => {
const defaultV = '#2e55ef';
if (!rule) {
return defaultV;
@@ -217,29 +216,24 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
};
return (
<div>
<div className={stylesBase.title}>{localeService.t('sheet.cf.panel.styleRule')}</div>
<div
className={`
${styles.cfPreviewWrap}
`}
>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<div className={previewClassName}>
<Preview rule={getResult({ minType, medianType, maxType, minValue, medianValue, maxValue, minColor, medianColor, maxColor }) as IConditionalFormattingRuleConfig} />
</div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.valueType.min')}</div>
<div
className={clsx(`
${stylesBase.labelContainer}
univer-mt-3
`, 'univer-box-border univer-h-8')}
>
<div className="univer-mt-3 univer-text-xs univer-text-gray-600">
{localeService.t('sheet.cf.valueType.min')}
</div>
<div className="univer-mt-3 univer-flex univer-h-8 univer-items-center">
<Select
className="univer-flex-shrink-0"
options={minOptions}
value={minType}
onChange={(v) => {
minTypeSet(v as CFValueType);
setMinType(v as CFValueType);
const value = createDefaultValueByValueType(v as CFValueType, 10);
minValueSet(value);
setMinValue(value);
handleChange({ minType: v as CFValueType, medianType, maxType, minValue: value, medianValue, maxValue, minColor, medianColor, maxColor });
}}
/>
@@ -249,7 +243,7 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
value={minValue}
type={minType}
onChange={(v) => {
minValueSet(v);
setMinValue(v);
handleChange({ minType, medianType, maxType, minValue: v, medianValue, maxValue, minColor, medianColor, maxColor });
}}
/>
@@ -257,27 +251,32 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
className="univer-ml-1"
color={minColor}
onChange={(v) => {
minColorSet(v);
setMinColor(v);
handleChange({ minType, medianType, maxType, minValue, medianValue, maxValue, minColor: v, medianColor, maxColor });
}}
/>
</div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.panel.medianValue')}</div>
<div
className={clsx(`
${stylesBase.labelContainer}
univer-mt-3
`, 'univer-box-border univer-h-8')}
>
<div className="univer-mt-3 univer-text-xs univer-text-gray-600">{localeService.t('sheet.cf.panel.medianValue')}</div>
<div className="univer-mt-3 univer-flex univer-h-8 univer-items-center">
<Select
className="univer-flex-shrink-0"
options={medianOptions}
value={medianType}
onChange={(v) => {
medianTypeSet(v as CFValueType);
setMedianType(v as CFValueType);
const value = createDefaultValueByValueType(v as CFValueType, 50);
medianValueSet(value);
handleChange({ minType, medianType: v as CFValueType, maxType, minValue, medianValue: value, maxValue, minColor, medianColor, maxColor });
setMedianValue(value);
handleChange({
minType,
medianType: v as CFValueType,
maxType,
minValue,
medianValue: value,
maxValue,
minColor,
medianColor,
maxColor,
});
}}
/>
@@ -287,8 +286,18 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
value={medianValue}
type={medianType}
onChange={(v) => {
medianValueSet(v);
handleChange({ minType, medianType, maxType, minValue, medianValue: v, maxValue, minColor, medianColor, maxColor });
setMedianValue(v);
handleChange({
minType,
medianType,
maxType,
minValue,
medianValue: v,
maxValue,
minColor,
medianColor,
maxColor,
});
}}
/>
{medianType !== 'none' && (
@@ -296,29 +305,44 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
className="univer-ml-1"
color={medianColor}
onChange={(v) => {
medianColorSet(v);
handleChange({ minType, medianType, maxType, minValue, medianValue, maxValue, minColor, medianColor: v, maxColor });
setMedianColor(v);
handleChange({
minType,
medianType,
maxType,
minValue,
medianValue,
maxValue,
minColor,
medianColor: v,
maxColor,
});
}}
/>
)}
</div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.valueType.max')}</div>
<div
className={clsx(`
${stylesBase.labelContainer}
univer-mt-3 univer-box-border univer-h-8
`)}
>
<div className="univer-mt-3 univer-text-xs univer-text-gray-600">{localeService.t('sheet.cf.valueType.max')}</div>
<div className="univer-mt-3 univer-flex univer-h-8 univer-items-center">
<Select
className="univer-flex-shrink-0"
options={maxOptions}
value={maxType}
onChange={(v) => {
maxTypeSet(v as CFValueType);
setMaxType(v as CFValueType);
const value = createDefaultValueByValueType(v as CFValueType, 90);
maxValueSet(value);
handleChange({ minType, medianType, maxType: v as CFValueType, minValue, medianValue, maxValue: value, minColor, medianColor, maxColor });
setMaxValue(value);
handleChange({
minType,
medianType,
maxType: v as CFValueType,
minValue,
medianValue,
maxValue: value,
minColor,
medianColor,
maxColor,
});
}}
/>
<TextInput
@@ -327,20 +351,39 @@ export const ColorScaleStyleEditor = (props: IStyleEditorProps) => {
value={maxValue}
type={maxType}
onChange={(v) => {
maxValueSet(v);
handleChange({ minType, medianType, maxType, minValue, medianValue, maxValue: v, minColor, medianColor, maxColor });
setMaxValue(v);
handleChange({
minType,
medianType,
maxType,
minValue,
medianValue,
maxValue: v,
minColor,
medianColor,
maxColor,
});
}}
/>
<ColorPicker
className="univer-ml-1"
color={maxColor}
onChange={(v) => {
maxColorSet(v);
handleChange({ minType, medianType, maxType, minValue, medianValue, maxValue, minColor, medianColor, maxColor: v });
setMaxColor(v);
handleChange({
minType,
medianType,
maxType,
minValue,
medianValue,
maxValue,
minColor,
medianColor,
maxColor: v,
});
}}
/>
</div>
</div>
);
};
@@ -26,8 +26,7 @@ import { useDependency, useSidebarClick } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
import { ColorPicker } from '../../color-picker';
import { Preview } from '../../preview';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
import { previewClassName } from './styles';
const createOptionItem = (text: CFValueType, localeService: LocaleService) => ({ label: localeService.t(`sheet.cf.valueType.${text}`), value: text });
@@ -38,11 +37,11 @@ const InputText = (props: { disabled?: boolean; id: string; className: string; t
const subUnitId = univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet()?.getSheetId();
const formulaEditorRef = useRef<IFormulaEditorRef>(null);
const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false);
const [isFocusFormulaEditor, setIsFocusFormulaEditor] = useState(false);
useSidebarClick((e: MouseEvent) => {
const isOutSide = formulaEditorRef.current?.isClickOutSide(e);
isOutSide && isFocusFormulaEditorSet(false);
isOutSide && setIsFocusFormulaEditor(false);
});
const _value = useRef(value);
@@ -58,10 +57,11 @@ const InputText = (props: { disabled?: boolean; id: string; className: string; t
max: Number.MAX_SAFE_INTEGER,
};
}, [type]);
if (type === CFValueType.formula) {
const v = String(_value.current).startsWith('=') ? String(_value.current) || '' : '=';
return (
<div style={{ width: '100%', marginLeft: 12 }}>
<div className="univer-ml-3 univer-w-full">
<FormulaEditor
initValue={v as any}
unitId={unitId}
@@ -71,7 +71,7 @@ const InputText = (props: { disabled?: boolean; id: string; className: string; t
const formula = v || '';
onChange(formula);
}}
onFocus={() => isFocusFormulaEditorSet(true)}
onFocus={() => setIsFocusFormulaEditor(true)}
ref={formulaEditorRef}
/>
</div>
@@ -224,27 +224,29 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
return (
<div>
<div className={stylesBase.title}>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<div
className={`
${styles.cfPreviewWrap}
`}
>
<Preview rule={getResult({ isGradient, minValue, minValueType, maxValue, maxValueType, positiveColor, nativeColor, isShowValue }) as IConditionalFormattingRuleConfig} />
<div className={previewClassName}>
<Preview
rule={getResult({
isGradient,
minValue,
minValueType,
maxValue,
maxValueType,
positiveColor,
nativeColor,
isShowValue,
}) as IConditionalFormattingRuleConfig}
/>
</div>
<div>
<div className={stylesBase.label}>
<div className="univer-mt-3 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.fillType')}
</div>
<div
className={`
univer-ml-1 univer-mt-3
${stylesBase.labelContainer}
`}
>
<div className="univer-ml-1 univer-mt-3 univer-flex univer-items-center">
<RadioGroup
value={isGradient}
onChange={(v) => {
@@ -253,23 +255,27 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
}}
>
<Radio value="0">
<span className={styles.text}>{localeService.t('sheet.cf.panel.pureColor')}</span>
<span className="univer-text-xs">{localeService.t('sheet.cf.panel.pureColor')}</span>
</Radio>
<Radio value="1">
<span className={styles.text}>{localeService.t('sheet.cf.panel.gradient')}</span>
<span className="univer-text-xs">{localeService.t('sheet.cf.panel.gradient')}</span>
</Radio>
</RadioGroup>
<div
className={`
${styles.utilItem}
univer-ml-6
`}
>
<div className="univer-ml-6 univer-flex univer-items-center univer-text-xs">
<Checkbox
checked={!isShowValue}
onChange={(v) => {
setIsShowValue(!v);
_handleChange({ isGradient: v as string, minValue, minValueType, maxValue, maxValueType, positiveColor, nativeColor, isShowValue: !v });
_handleChange({
isGradient: v as string,
minValue,
minValueType,
maxValue,
maxValueType,
positiveColor,
nativeColor,
isShowValue: !v,
});
}}
/>
{localeService.t('sheet.cf.panel.onlyShowDataBar')}
@@ -277,23 +283,10 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
</div>
</div>
<div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.panel.colorSet')}</div>
<div
className={`
${stylesBase.labelContainer}
univer-ml-1 univer-mt-3
`}
>
<div
className={`
${stylesBase.labelContainer}
`}
>
<div
className={`
${styles.text}
`}
>
<div className="univer-mt-3 univer-text-sm univer-text-gray-600">{localeService.t('sheet.cf.panel.colorSet')}</div>
<div className="univer-ml-1 univer-mt-3 univer-flex univer-items-center">
<div className="univer-flex univer-items-center">
<div className="univer-text-xs">
{localeService.t('sheet.cf.panel.native')}
</div>
<ColorPicker
@@ -301,17 +294,8 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
onChange={handleNativeColorChange}
/>
</div>
<div
className={`
${stylesBase.labelContainer}
univer-ml-3
`}
>
<div
className={`
${styles.text}
`}
>
<div className="univer-ml-3 univer-flex univer-items-center">
<div className="univer-text-xs">
{localeService.t('sheet.cf.panel.positive')}
</div>
<ColorPicker
@@ -323,7 +307,7 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
</div>
<div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.valueType.min')}</div>
<div className="univer-mt-3 univer-text-sm univer-text-gray-600">{localeService.t('sheet.cf.valueType.min')}</div>
<div className="univer-mt-3 univer-flex univer-items-center">
<Select
className="univer-w-1/2 univer-flex-shrink-0"
@@ -333,23 +317,41 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
setMinValueType(v as CFValueType);
const value = createDefaultValueByValueType(v as CFValueType, 10);
minValueSet(value);
_handleChange({ isGradient, minValue: value, minValueType: v as CFValueType, maxValue, maxValueType, positiveColor, nativeColor, isShowValue });
_handleChange({
isGradient,
minValue: value,
minValueType: v as CFValueType,
maxValue,
maxValueType,
positiveColor,
nativeColor,
isShowValue,
});
}}
/>
<InputText
disabled={!isShowInput(minValueType)}
id="min"
type={minValueType}
className="univer-ml-3"
disabled={!isShowInput(minValueType)}
type={minValueType}
value={minValue}
onChange={(v) => {
minValueSet(v || 0);
_handleChange({ isGradient, minValue: v || 0, minValueType, maxValue, maxValueType, positiveColor, nativeColor, isShowValue });
_handleChange({
isGradient,
minValue: v || 0,
minValueType,
maxValue,
maxValueType,
positiveColor,
nativeColor,
isShowValue,
});
}}
/>
</div>
<div className={stylesBase.label}>{localeService.t('sheet.cf.valueType.max')}</div>
<div className="univer-mt-3 univer-text-sm univer-text-gray-600">{localeService.t('sheet.cf.valueType.max')}</div>
<div className="univer-mt-3 univer-flex univer-items-center">
<Select
className="univer-w-1/2 univer-flex-shrink-0"
@@ -359,7 +361,16 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
setMaxValueType(v as CFValueType);
const value = createDefaultValueByValueType(v as CFValueType, 90);
setMaxValue(value);
_handleChange({ isGradient, minValue, minValueType, maxValue: value, maxValueType: v as CFValueType, positiveColor, nativeColor, isShowValue });
_handleChange({
isGradient,
minValue,
minValueType,
maxValue: value,
maxValueType: v as CFValueType,
positiveColor,
nativeColor,
isShowValue,
});
}}
/>
<InputText
@@ -370,12 +381,20 @@ export const DataBarStyleEditor = (props: IStyleEditorProps) => {
value={maxValue}
onChange={(v) => {
setMaxValue(v || 0);
_handleChange({ isGradient, minValue, minValueType, maxValue: v || 0, maxValueType, positiveColor, nativeColor, isShowValue });
_handleChange({
isGradient,
minValue,
minValueType,
maxValue: v || 0,
maxValueType,
positiveColor,
nativeColor,
isShowValue,
});
}}
/>
</div>
</div>
</div>
);
};
@@ -25,8 +25,7 @@ import { useDependency, useSidebarClick } from '@univerjs/ui';
import { useEffect, useRef, useState } from 'react';
import { ConditionalStyleEditor } from '../../conditional-style-editor';
import { Preview } from '../../preview';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
import { previewClassName } from './styles';
export const FormulaStyleEditor = (props: IStyleEditorProps) => {
const { onChange, interceptorManager } = props;
@@ -38,16 +37,16 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => {
const rule = props.rule?.type === CFRuleType.highlightCell ? props.rule : undefined as IRankHighlightCell | IAverageHighlightCell | undefined;
const divEleRef = useRef<HTMLDivElement>(null);
const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false);
const [isFocusFormulaEditor, setIsFocusFormulaEditor] = useState(false);
const formulaEditorRef = useRef<IFormulaEditorRef>(null);
const [style, styleSet] = useState<IHighlightCell['style']>({});
const [formula, formulaSet] = useState(() => {
const [style, setStyle] = useState<IHighlightCell['style']>({});
const [formula, setFormula] = useState(() => {
if (rule?.subType === CFSubRuleType.formula) {
return rule.value;
}
return '=';
});
const [formulaError, formulaErrorSet] = useState<string | undefined>(undefined);
const [formulaError, setFormulaError] = useState<string | undefined>(undefined);
const getResult = (config: {
style: IHighlightCell['style'];
@@ -73,7 +72,7 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => {
const dispose = interceptorManager.intercept(interceptorManager.getInterceptPoints().beforeSubmit, {
handler: (v, _c, next) => {
if (formulaError || formula.length === 1 || !formula.startsWith('=')) {
formulaErrorSet(localeService.t('sheet.cf.errorMessage.formulaError'));
setFormulaError(localeService.t('sheet.cf.errorMessage.formulaError'));
return false;
}
return next(v);
@@ -91,34 +90,29 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => {
useSidebarClick((e: MouseEvent) => {
const isOutSide = formulaEditorRef.current?.isClickOutSide(e);
isOutSide && isFocusFormulaEditorSet(false);
isOutSide && setIsFocusFormulaEditor(false);
});
return (
<div ref={divEleRef}>
<div
className={`
${stylesBase.title}
univer-mt-4
`}
>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<div className="univer-mt-3">
<FormulaEditor
onChange={(formula) => {
formulaSet(formula);
setFormula(formula);
_onChange({ style, formula });
}}
onVerify={(result, formula) => {
if (!result || formula.length === 1) {
formulaErrorSet(localeService.t('sheet.cf.errorMessage.formulaError'));
setFormulaError(localeService.t('sheet.cf.errorMessage.formulaError'));
} else {
formulaErrorSet(undefined);
setFormulaError(undefined);
}
}}
errorText={formulaError}
onFocus={() => { isFocusFormulaEditorSet(true); }}
onFocus={() => { setIsFocusFormulaEditor(true); }}
isFocus={isFocusFormulaEditor}
initValue={formula as any}
unitId={workbook.getUnitId()}
@@ -128,18 +122,14 @@ export const FormulaStyleEditor = (props: IStyleEditorProps) => {
</div>
<div
className={`
${styles.cfPreviewWrap}
`}
>
<div className={previewClassName}>
<Preview rule={getResult({ style, formula }) as IConditionalFormattingRuleConfig} />
</div>
<ConditionalStyleEditor
style={rule?.style}
className="univer-mt-3"
onChange={(v) => {
styleSet(v);
setStyle(v);
_onChange({ style: v, formula });
}}
/>
@@ -33,12 +33,11 @@ import {
createDefaultValue,
} from '@univerjs/sheets-conditional-formatting';
import { useDependency } from '@univerjs/ui';
import React, { useEffect, useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { ConditionalStyleEditor } from '../../conditional-style-editor';
import { Preview } from '../../preview';
import { WrapperError } from '../../wrapper-error/WrapperError';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
import { previewClassName } from './styles';
const createOptionItem = (text: string, localeService: LocaleService) => ({ label: localeService.t(`sheet.cf.operator.${text}`), value: text });
type IValue = number | string | [number, number];
@@ -55,16 +54,16 @@ const HighlightCellInput = (props: {
const { type, operator, onChange, value, interceptorManager } = props;
const localeService = useDependency(LocaleService);
const [inputNumberValue, inputNumberValueSet] = useState(() => typeof value === 'number' ? value : 0);
const [numberError, numberErrorSet] = useState('');
const [inputNumberValue, setInputNumberValue] = useState(() => typeof value === 'number' ? value : 0);
const [numberError, setNumberError] = useState('');
const [inputTextValue, inputTextValueSet] = useState(() => typeof value === 'string' ? value : '');
const [textError, textErrorSet] = useState('');
const [inputNumberMin, inputNumberMinSet] = useState(() => Array.isArray(value) ? value[0] === undefined ? 0 : value[0] : 0);
const [numberMinError, numberMinErrorSet] = useState('');
const [inputTextValue, setInputTextValue] = useState(() => typeof value === 'string' ? value : '');
const [textError, setTextError] = useState('');
const [inputNumberMin, setInputNumberMin] = useState(() => Array.isArray(value) ? value[0] === undefined ? 0 : value[0] : 0);
const [numberMinError, setNumberMinError] = useState('');
const [inputNumberMax, inputNumberMaxSet] = useState(() => Array.isArray(value) ? value[1] === undefined ? 100 : value[1] : 100);
const [numberMaxError, numberMaxErrorSet] = useState('');
const [inputNumberMax, setInputNumberMax] = useState(() => Array.isArray(value) ? value[1] === undefined ? 100 : value[1] : 100);
const [numberMaxError, setNumberMaxError] = useState('');
useEffect(() => {
switch (type) {
@@ -93,7 +92,7 @@ const HighlightCellInput = (props: {
case CFSubRuleType.text: {
if ([CFTextOperator.beginsWith, CFTextOperator.containsText, CFTextOperator.endsWith, CFTextOperator.notEqual, CFTextOperator.notContainsText, CFTextOperator.equal].includes(operator as any)) {
if (!inputTextValue) {
textErrorSet(localeService.t('sheet.cf.errorMessage.notBlank'));
setTextError(localeService.t('sheet.cf.errorMessage.notBlank'));
return false;
}
return next(v);
@@ -112,7 +111,7 @@ const HighlightCellInput = (props: {
case CFSubRuleType.text: {
if ([CFTextOperator.beginsWith, CFTextOperator.endsWith, CFTextOperator.containsText, CFTextOperator.notContainsText, CFTextOperator.equal, CFTextOperator.notEqual].includes(operator as CFTextOperator)) {
const _onChange = (value: string) => {
inputTextValueSet(value);
setInputTextValue(value);
onChange(value);
};
return (
@@ -121,7 +120,7 @@ const HighlightCellInput = (props: {
<Input
value={inputTextValue}
onChange={(v) => {
textErrorSet('');
setTextError('');
_onChange(v);
}}
/>
@@ -134,9 +133,9 @@ const HighlightCellInput = (props: {
case CFSubRuleType.number: {
if ([CFNumberOperator.equal, CFNumberOperator.notEqual, CFNumberOperator.greaterThan, CFNumberOperator.greaterThanOrEqual, CFNumberOperator.lessThan, CFNumberOperator.lessThanOrEqual].includes(operator as CFNumberOperator)) {
const _onChange = (value: number | null) => {
inputNumberValueSet(value || 0);
setInputNumberValue(value || 0);
onChange(value || 0);
numberErrorSet('');
setNumberError('');
};
return (
<div className="univer-mt-3">
@@ -154,24 +153,19 @@ const HighlightCellInput = (props: {
}
if ([CFNumberOperator.between, CFNumberOperator.notBetween].includes(operator as CFNumberOperator)) {
const onChangeMin = (_value: number | null) => {
inputNumberMinSet(_value || 0);
setInputNumberMin(_value || 0);
const value: [number, number] = [_value || 0, inputNumberMax];
onChange(value);
numberMinErrorSet('');
setNumberMinError('');
};
const onChangeMax = (_value: number | null) => {
inputNumberMaxSet(_value || 0);
setInputNumberMax(_value || 0);
const value: [number, number] = [inputNumberMin, _value || 0];
onChange(value);
numberMaxErrorSet('');
setNumberMaxError('');
};
return (
<div
className={`
univer-mt-3
${stylesBase.labelContainer}
`}
>
<div className="univer-mt-3 univer-flex univer-items-center">
<WrapperError errorText={numberMinError}>
<InputNumber min={Number.MIN_SAFE_INTEGER} max={Number.MAX_SAFE_INTEGER} value={inputNumberMin} onChange={onChangeMin} />
</WrapperError>
@@ -285,7 +279,7 @@ export const HighlightCellStyleEditor = (props: IStyleEditorProps<any, ITextHigh
return v;
});
const [style, styleSet] = useState<IHighlightCell['style']>({});
const [style, setStyle] = useState<IHighlightCell['style']>({});
const getResult = useMemo(() => (option: { subType?: string; operator?: string; value?: IValue; style?: IHighlightCell['style'] }) => {
switch (option.subType || subType) {
@@ -373,12 +367,7 @@ export const HighlightCellStyleEditor = (props: IStyleEditorProps<any, ITextHigh
return (
<div>
<div
className={`
${stylesBase.title}
univer-mt-4
`}
>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<div className="univer-flex univer-justify-between univer-gap-4">
@@ -397,19 +386,23 @@ export const HighlightCellStyleEditor = (props: IStyleEditorProps<any, ITextHigh
/>
)}
</div>
<HighlightCellInput key={inputRenderKey} value={value} interceptorManager={interceptorManager} type={subType} operator={operator} rule={rule} onChange={onInputChange} />
<div
className={`
${styles.cfPreviewWrap}
`}
>
<HighlightCellInput
key={inputRenderKey}
value={value}
interceptorManager={interceptorManager}
type={subType}
operator={operator}
rule={rule}
onChange={onInputChange}
/>
<div className={previewClassName}>
<Preview rule={getResult({}) as IConditionalFormattingRuleConfig} />
</div>
<ConditionalStyleEditor
style={rule?.style}
className="univer-ml-1"
onChange={(v) => {
styleSet(v);
setStyle(v);
onChange(getResult({ style: v }));
}}
/>
@@ -36,8 +36,6 @@ import {
import { FormulaEditor } from '@univerjs/sheets-formula-ui';
import { ILayoutService, useDependency, useScrollYOverContainer, useSidebarClick } from '@univerjs/ui';
import { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
const getIcon = (iconType: string, iconId: string | number) => {
const arr = iconMap[iconType] || [];
@@ -45,15 +43,11 @@ const getIcon = (iconType: string, iconId: string | number) => {
};
const TextInput = (props: { id: number; type: CFValueType; value: number | string; onChange: (v: number | string) => void; error?: string }) => {
const { error, type, onChange } = props;
const univerInstanceService = useDependency(IUniverInstanceService);
const unitId = univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET)!.getUnitId();
const subUnitId = univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet()?.getSheetId();
const className = useMemo(() => {
if (props.error) {
return styles.errorInput;
}
return '';
}, [props.error]);
const formulaEditorRef = useRef<IFormulaEditorRef>(null);
const [isFocusFormulaEditor, isFocusFormulaEditorSet] = useState(false);
@@ -63,14 +57,20 @@ const TextInput = (props: { id: number; type: CFValueType; value: number | strin
isOutSide && isFocusFormulaEditorSet(false);
});
return (
<div className={styles.positionRelative}>
{props.type !== CFValueType.formula
<div className="univer-relative">
{type !== CFValueType.formula
? (
<>
<InputNumber className={className} value={Number(props.value) || 0} onChange={(v) => props.onChange(v ?? 0)} />
{props.error && (
<div className={styles.errorText}>
{props.error}
<InputNumber
className={clsx({
'univer-border-red-500': error,
})}
value={Number(props.value) || 0}
onChange={(v) => onChange(v ?? 0)}
/>
{error && (
<div className="univer-absolute univer-text-xs univer-text-red-500">
{error}
</div>
)}
</>
@@ -78,16 +78,16 @@ const TextInput = (props: { id: number; type: CFValueType; value: number | strin
: (
<div className="univer-w-full">
<FormulaEditor
ref={formulaEditorRef}
initValue={String(props.value) as any}
unitId={unitId}
subUnitId={subUnitId}
isFocus={isFocusFormulaEditor}
onChange={(v = '') => {
const formula = v || '';
props.onChange(formula);
onChange(formula);
}}
onFocus={() => isFocusFormulaEditorSet(true)}
ref={formulaEditorRef}
/>
</div>
)}
@@ -101,35 +101,46 @@ const createDefaultConfigItem = (iconType: IIconType, index: number, list: unkno
iconId: String(index),
});
interface IconGroupListProps {
interface IIconGroupListProps {
onClick: (iconType: IIconType) => void;
iconType?: IIconType;
};
const IconGroupList = forwardRef<HTMLDivElement, IconGroupListProps>((props, ref) => {
const IconGroupList = forwardRef<HTMLDivElement, IIconGroupListProps>((props, ref) => {
const { onClick } = props;
const localeService = useDependency(LocaleService);
const handleClick = (iconType: IIconType) => {
props.onClick(iconType);
onClick(iconType);
};
return (
<div ref={ref} className={styles.iconGroupList}>
<div ref={ref} className="univer-w-80">
{iconGroup.map((group, index) => {
return (
<div key={index} className={styles.group}>
<div className={styles.title}>{localeService.t(group.title)}</div>
<div className={styles.itemContent}>
<div key={index} className="univer-mb-3">
<div className="univer-mb-1 univer-text-sm">{localeService.t(group.title)}</div>
<div className="univer-flex univer-flex-wrap">
{group.group.map((groupItem) => {
return (
<div className={styles.itemWrap} key={groupItem.name} onClick={() => { handleClick(groupItem.name); }}>
<div className={styles.item}>
<div
key={groupItem.name}
className="univer-mb-1 univer-flex univer-w-1/2 univer-items-center"
onClick={() => { handleClick(groupItem.name); }}
>
<a
className={`
univer-cursor-pointer univer-rounded
hover:univer-bg-gray-100
`}
>
{groupItem.list.map((base64, index) => (
<img
key={index}
className="univer-size-5"
src={base64}
draggable={false}
/>
))}
</div>
</a>
</div>
);
})}
@@ -143,6 +154,8 @@ const IconGroupList = forwardRef<HTMLDivElement, IconGroupListProps>((props, ref
});
const IconItemList = (props: { onClick: (iconType: IIconType, iconId: string) => void; iconType?: IIconType; iconId: string }) => {
const { onClick } = props;
const list = useMemo(() => {
const result: { iconType: IIconType; iconId: string; base64: string }[] = [];
for (const key in iconMap) {
@@ -158,28 +171,40 @@ const IconItemList = (props: { onClick: (iconType: IIconType, iconId: string) =>
}
return result;
}, []);
const handleClick = (item: typeof list[0]) => {
props.onClick(item.iconType, item.iconId);
onClick(item.iconType, item.iconId);
};
return (
<div className={styles.iconItemListWrap}>
<div className={styles.none} onClick={() => handleClick({ iconType: EMPTY_ICON_TYPE as any, iconId: '', base64: '' })}>
<div>
<div
className="univer-mb-2.5 univer-flex univer-cursor-pointer univer-items-center univer-pl-1"
onClick={() => handleClick({ iconType: EMPTY_ICON_TYPE as any, iconId: '', base64: '' })}
>
<SlashSingle className="univer-size-5" />
<span>无单元格图标</span>
<span className="univer-ml-2">无单元格图标</span>
</div>
<div className={styles.iconItemList}>
<div className="univer-flex univer-w-64 univer-flex-wrap">
{list.map((item) => (
<div key={`${item.iconType}_${item.iconId}`} className={styles.item}>
<div
key={`${item.iconType}_${item.iconId}`}
className={`
univer-mb-2 univer-mr-2 univer-flex univer-cursor-pointer univer-items-center
univer-justify-center univer-rounded
hover:univer-bg-gray-100
`}
>
<img
className="univer-size-5"
onClick={() => handleClick(item)}
src={item.base64}
draggable={false}
onClick={() => handleClick(item)}
/>
</div>
))}
</div>
</div>
);
};
@@ -235,8 +260,8 @@ const IconSetRuleEdit = (props: {
>
<div
className={`
${stylesBase.label}
univer-flex univer-items-center univer-justify-between
univer-mt-3 univer-flex univer-items-center univer-justify-between univer-text-sm
univer-text-gray-600
`}
>
<div
@@ -250,7 +275,7 @@ const IconSetRuleEdit = (props: {
<>
{!isFirst && !isEnd && localeService.t('sheet.cf.iconSet.rule')}
{!isFirst && !isEnd && (
<span className={styles.stress}>
<span className="univer-font-medium univer-text-gray-600">
(
{localeService.t('sheet.cf.iconSet.when')}
{localeService.t(`sheet.cf.symbol.${getOppositeOperator(preItem.operator)}`)}
@@ -272,8 +297,22 @@ const IconSetRuleEdit = (props: {
</div>
)}
>
<div className={clsx(styles.dropdownIcon, 'univer-box-border univer-h-7')}>
{icon ? <img src={icon} className={styles.icon} /> : <SlashSingle className={styles.icon} />}
<div
className={`
univer-box-border univer-flex univer-h-8 univer-w-full univer-items-center
univer-justify-between univer-rounded-md univer-border univer-border-solid
univer-border-gray-200 univer-bg-white univer-px-4 univer-py-2 univer-text-xs
univer-text-gray-600 univer-transition-all
hover:univer-border-primary-600
`}
>
{icon
? <img src={icon} className="univer-size-4" draggable={false} />
: (
<SlashSingle
className="univer-size-4"
/>
)}
<MoreDownSingle />
</div>
</Dropdown>
@@ -287,15 +326,9 @@ const IconSetRuleEdit = (props: {
/>
)
: (
<div
className={`
univer-w-[45%]
${stylesBase.label}
`}
style={{ marginTop: 0 }}
>
<div className="univer-mt-0 univer-w-[45%] univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.iconSet.rule')}
<span className={styles.stress}>
<span className="univer-font-medium univer-text-gray-600">
{localeService.t('sheet.cf.iconSet.when')}
{localeService.t(`sheet.cf.symbol.${getOppositeOperator(preItem.operator)}`)}
{lessThanText}
@@ -309,9 +342,8 @@ const IconSetRuleEdit = (props: {
<>
<div
className={`
univer-mt-3
${stylesBase.label}
univer-flex univer-items-center univer-justify-between univer-gap-4
univer-mt-3 univer-flex univer-items-center univer-justify-between univer-gap-4
univer-text-sm univer-text-gray-600
`}
>
<div>
@@ -515,11 +547,11 @@ export const IconSet = (props: IStyleEditorProps<unknown, IIconSet>) => {
useScrollYOverContainer(iconGroupListEl, layoutService.rootContainerElement);
return (
<div className={styles.iconSet}>
<div className={stylesBase.title}>{localeService.t('sheet.cf.panel.styleRule')}</div>
<div
className="univer-mt-3"
>
<div>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<div className="univer-mt-3">
<Dropdown
overlay={(
<div className="univer-rounded-lg univer-p-4">
@@ -533,28 +565,26 @@ export const IconSet = (props: IStyleEditorProps<unknown, IIconSet>) => {
</div>
)}
>
<div className={clsx(styles.dropdownIcon, 'univer-box-border univer-h-7 univer-w-auto')}>
<div
className={clsx(`
univer-box-border univer-flex univer-h-8 univer-w-full univer-items-center
univer-justify-between univer-rounded-md univer-border univer-border-solid
univer-border-gray-200 univer-bg-white univer-px-4 univer-py-2 univer-text-xs
univer-text-gray-600 univer-transition-all
hover:univer-border-primary-600
`)}
>
{previewIcon}
<MoreDownSingle />
</div>
</Dropdown>
</div>
<div
className={`
univer-mt-3
${styles.renderConfig}
`}
>
<div className={styles.utilItem}>
<div className="univer-mt-3 univer-flex univer-items-center univer-text-xs">
<div className="univer-flex univer-items-center univer-text-xs">
<Checkbox onChange={reverseIcon} />
{localeService.t('sheet.cf.iconSet.reverseIconOrder')}
</div>
<div
className={`
${styles.utilItem}
univer-ml-6
`}
>
<div className="univer-ml-6 univer-flex univer-items-center univer-text-xs">
<Checkbox checked={!isShowValue} onChange={(v) => { isShowValueSet(!v); }} />
{localeService.t('sheet.cf.iconSet.onlyShowIcon')}
</div>
@@ -20,11 +20,10 @@ import { LocaleService } from '@univerjs/core';
import { Checkbox, InputNumber, Select } from '@univerjs/design';
import { CFNumberOperator, CFRuleType, CFSubRuleType } from '@univerjs/sheets-conditional-formatting';
import { useDependency } from '@univerjs/ui';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { ConditionalStyleEditor } from '../../conditional-style-editor';
import { Preview } from '../../preview';
import stylesBase from '../index.module.less';
import styles from './index.module.less';
import { previewClassName } from './styles';
export const RankStyleEditor = (props: IStyleEditorProps) => {
const { onChange, interceptorManager } = props;
@@ -33,7 +32,7 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
const rule = props.rule?.type === CFRuleType.highlightCell ? props.rule : undefined as IRankHighlightCell | IAverageHighlightCell | undefined;
const options = [{ label: localeService.t('sheet.cf.panel.isNotBottom'), value: 'isNotBottom' }, { label: localeService.t('sheet.cf.panel.isBottom'), value: 'isBottom' }, { label: localeService.t('sheet.cf.panel.greaterThanAverage'), value: 'greaterThanAverage' }, { label: localeService.t('sheet.cf.panel.lessThanAverage'), value: 'lessThanAverage' }];
const [type, typeSet] = useState(() => {
const [type, setType] = useState(() => {
const defaultV = options[0].value;
const type = rule?.type;
if (!rule) {
@@ -64,7 +63,7 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
}
return defaultV;
});
const [value, valueSet] = useState(() => {
const [value, setValue] = useState(() => {
const defaultV = 10;
const type = rule?.type;
if (!rule) {
@@ -82,7 +81,7 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
}
return defaultV;
});
const [isPercent, isPercentSet] = useState(() => {
const [isPercent, setIsPercent] = useState(() => {
const defaultV = false;
const type = rule?.type;
if (!rule) {
@@ -101,7 +100,7 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
return defaultV;
});
const [style, styleSet] = useState<IHighlightCell['style']>({});
const [style, setStyle] = useState<IHighlightCell['style']>({});
const getResult = (config: {
type: string;
@@ -142,12 +141,7 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
};
return (
<div>
<div
className={`
${stylesBase.title}
univer-mt-4
`}
>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleRule')}
</div>
<Select
@@ -155,38 +149,29 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
value={type}
options={options}
onChange={(v) => {
typeSet(v);
setType(v);
_onChange({ type: v, isPercent, value, style });
}}
/>
{['isNotBottom', 'isBottom'].includes(type) && (
<div
className={`
${stylesBase.labelContainer}
univer-mt-3
`}
>
<div className="univer-mt-3 univer-flex univer-items-center">
<InputNumber
min={1}
max={1000}
value={value}
onChange={(v) => {
const value = v || 0;
valueSet(value);
setValue(value);
_onChange({ type, isPercent, value, style });
}}
/>
<div
className={`
univer-ml-3
${stylesBase.labelContainer}
${styles.text}
`}
className="univer-ml-3 univer-flex univer-items-center univer-text-xs"
>
<Checkbox
checked={isPercent}
onChange={(v) => {
isPercentSet(!!v);
setIsPercent(!!v);
_onChange({ type, isPercent: !!v, value, style });
}}
/>
@@ -195,18 +180,14 @@ export const RankStyleEditor = (props: IStyleEditorProps) => {
</div>
)}
<div
className={`
${styles.cfPreviewWrap}
`}
>
<div className={previewClassName}>
<Preview rule={getResult({ type, isPercent, value, style }) as IConditionalFormattingRuleConfig} />
</div>
<ConditionalStyleEditor
style={rule?.style}
className="univer-mt-3"
onChange={(v) => {
styleSet(v);
setStyle(v);
_onChange({ type, isPercent, value, style: v });
}}
/>
@@ -1,169 +0,0 @@
.cf-rule-style-editor {
.cf-error-text {
color: rgb(var(--red-500));
font-size: var(--font-size-xxs);
margin-top: var(--margin-xxs);
}
.cf-preview-wrap {
margin-top: var(--margin-lg);
padding: var(--padding-xs) var(--padding-sm);
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-base);
}
.text {
font-size: var(--font-size-xxs);
}
.position-relative {
position: relative;
}
.btn-list {
display: flex;
justify-content: flex-end;
margin-bottom: var(--margin-base);
}
.util-item {
display: flex;
justify-content: flex-start;
align-items: center;
font-size: var(--font-size-xxs);
}
.icon-set {
.render-config {
display: flex;
align-items: center;
font-size: var(--font-size-xxs);
justify-content: flex-start;
}
.dropdown-icon {
background-color: rgb(var(--bg-color-secondary));
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-base);
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
padding: var(--padding-sm) var(--padding-lg);
font-size: var(--font-size-xxs);
color: rgb(var(--text-color-secondary));
transition: all 0.15s;
&:hover {
border-color: rgb(var(--primary-color)) !important;
}
.icon {
width: 16px;
height: 16px;
}
}
.error-input {
border: 1px solid rgb(var(--red-400));
}
.error-text {
color: rgb(var(--red-400));
font-size: 12px;
position: absolute;
}
}
}
.icon-group-list {
padding: var(--padding-base);
font-size: var(--font-size-xs);
box-sizing: border-box;
width: 328px;
background-color: rgb(var(--bg-color-secondary));
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-lg);
outline: none;
box-shadow: var(--box-shadow-base);
.title {
font-size: 13px;
margin-bottom: var(--margin-xxs);
}
.group {
margin-bottom: var(--margin-sm);
}
.item-content {
display: flex;
flex-wrap: wrap;
.item-wrap {
display: flex;
align-items: center;
justify-content: flex-start;
width: 50%;
margin-bottom: 4px;
.item {
border-radius: var(--border-radius-base);
cursor: pointer;
:not(:first-child).icon {
margin-left: 8px;
}
&:hover {
background-color: rgb(var(--bg-color-hover));
}
}
:not(:first-child).icon {
margin-left: 8px;
}
}
}
.icon {
width: 20px;
height: 20px;
}
}
.icon-item-list-wrap {
padding: var(--padding-base) 4px var(--padding-base) var(--padding-base);
font-size: var(--font-size-xs);
background-color: rgb(var(--bg-color-secondary));
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-lg);
outline: none;
box-shadow: var(--box-shadow-base);
.none {
display: flex;
align-items: center;
margin-bottom: 10px;
cursor: pointer;
padding-left: 4px;
span {
margin-left: 8px;
}
}
.icon-item-list {
display: flex;
width: 252px;
flex-wrap: wrap;
.item {
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--border-radius-base);
margin-right: 8px;
margin-bottom: 8px;
cursor: pointer;
&:hover {
background-color: rgb(var(--bg-color-hover));
}
}
.icon {
width: 20px;
height: 20px;
}
}
}
.width100 {
width: 100%;
}
.stress {
color: rgb(var(--text-color));
font-weight: 500;
}
@@ -26,13 +26,11 @@ import { AddCfCommand, CFRuleType, CFSubRuleType, ConditionalFormattingRuleModel
import { RangeSelector } from '@univerjs/sheets-formula-ui';
import { useDependency } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
import styleBase from '../index.module.less';
import { ColorScaleStyleEditor } from './ColorScale';
import { DataBarStyleEditor } from './DataBar';
import { FormulaStyleEditor } from './Formula';
import { HighlightCellStyleEditor } from './HighlightCell';
import { IconSet } from './IconSet';
import styles from './index.module.less';
import { RankStyleEditor } from './Rank';
import { beforeSubmit, submit } from './type';
@@ -231,8 +229,10 @@ export const RuleEdit = (props: IRuleEditProps) => {
}
};
return (
<div className={styles.cfRuleStyleEditor}>
<div className={styleBase.title}>{localeService.t('sheet.cf.panel.range')}</div>
<div>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.range')}
</div>
<div className="univer-mt-4">
<RangeSelector
unitId={unitId}
@@ -241,9 +241,11 @@ export const RuleEdit = (props: IRuleEditProps) => {
onChange={(_, text) => onRangeSelectorChange(text)}
onVerify={handleVerify}
/>
{errorText && <div className={styles.cfErrorText}>{errorText}</div>}
{errorText && <div className="univer-mt-1 univer-text-xs univer-text-red-500">{errorText}</div>}
</div>
<div className="univer-mt-4 univer-text-sm univer-text-gray-600">
{localeService.t('sheet.cf.panel.styleType')}
</div>
<div className={styleBase.title}>{localeService.t('sheet.cf.panel.styleType')}</div>
<Select
className="univer-mt-4 univer-w-full"
value={ruleType}
@@ -0,0 +1,17 @@
/**
* Copyright 2023-present DreamNum Co., Ltd.
*
* 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 const previewClassName = 'univer-mt-5 univer-px-1 univer-py-2 univer-border univer-border-solid univer-border-gray-200 univer-rounded';
@@ -14,9 +14,9 @@
* limitations under the License.
*/
import { createInterceptorKey } from '@univerjs/core';
import type { InterceptorManager } from '@univerjs/core';
import type { IConditionalFormattingRuleConfig } from '@univerjs/sheets-conditional-formatting';
import { createInterceptorKey } from '@univerjs/core';
export const beforeSubmit = createInterceptorKey<boolean, null>('beforeSubmit');
export const submit = createInterceptorKey<any, null>('submit');
@@ -1,137 +0,0 @@
.cf-rule-list {
.rule-selector {
color: rgb(var(--text-color-secondary));
font-size: 12px;
display: flex;
justify-content: space-between;
align-items: center;
.select {
color: rgb(var(--text-color));
width: 138px;
.select-selector {
border: none;
padding: 0;
}
.select-selection-item {
top: -2px;
left: 4px;
}
.select-selection-search-input {
cursor: pointer;
}
}
.btn-list {
font-size: 16px;
color: black;
display: flex;
justify-content: space-between;
align-items: center;
.gap {
margin-left: 8px;
}
.icon {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 4px 4px 4px 4px;
padding: 4px;
&:hover {
background: rgb(var(--grey-300));
}
}
.disabled {
color: rgb(var(--grey-500));
display: flex;
align-items: center;
border-radius: 4px 4px 4px 4px;
padding: 4px;
}
}
}
.rule-item {
padding: 8px 32px 8px 20px;
display: flex;
justify-content: space-between;
position: relative;
align-items: center;
border-radius: var(--border-radius-base);
.rule-describe {
max-width: 100%;
min-width: 0px;
overflow: hidden;
flex-shrink: 1;
font-size: var(--font-size-sm);
line-height: 21px;
.rule-type {
font-size: 14px;
line-height: 22px;
color: #1e222b;
}
.rule-range {
font-size: 12px;
line-height: 22px;
color: #7a7a7a;
}
}
&:hover {
background-color: rgb(var(--grey-100));
}
&.active {
background-color: rgb(var(--grey-100));
}
.draggableHandle {
display: none;
position: absolute;
left: 0px;
width: 20px;
height: 20px;
border-radius: var(--border-radius-base);
cursor: grab;
// &:hover {
// background-color: rgb(var(--grey-300));
// }
}
&:hover {
.delete-item {
display: flex;
align-items: center;
justify-content: center;
}
.draggableHandle {
display: flex;
align-items: center;
justify-content: center;
}
}
.delete-item {
display: none;
cursor: pointer;
border-radius: var(--border-radius-base);
position: absolute;
right: 4px;
width: 24px;
height: 24px;
&:hover {
background-color: rgb(var(--grey-300));
}
}
& .active {
display: flex;
align-items: center;
justify-content: center;
}
}
.grid-layout-wrap {
width: calc(100% - 2 * var(--padding-sm) + 2 * var(--padding-xl));
margin-left: calc(-1 * var(--padding-xl));
padding-left: var(--padding-sm);
.react-grid-item {
transition: none;
}
}
}
:global .react-grid-item.react-grid-placeholder {
background: rgb(var(--grey-300)) !important;
}
@@ -40,7 +40,6 @@ import GridLayout from 'react-grid-layout';
import { debounceTime, Observable } from 'rxjs';
import { ConditionalFormattingI18nController } from '../../../controllers/cf.i18n.controller';
import { Preview } from '../../preview';
import styles from './index.module.less';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
@@ -319,13 +318,13 @@ export const RuleList = (props: IRuleListProps) => {
}, [ruleList]);
return (
<div className={styles.cfRuleList}>
<div className={styles.ruleSelector}>
<div>
<div>
<div className="univer-flex univer-items-center univer-justify-between univer-gap-2 univer-text-sm">
<div className="univer-flex univer-items-center univer-gap-2">
{conditionalFormattingI18nController.tWithReactNode(
'sheet.cf.panel.managerRuleSelect',
<Select
className={styles.select}
className="univer-w-36"
options={selectOption}
value={selectValue}
onChange={(v) => { setSelectValue(v); }}
@@ -334,97 +333,119 @@ export const RuleList = (props: IRuleListProps) => {
</div>
<div className="univer-flex univer-justify-end">
<Tooltip title={localeService.t('sheet.cf.panel.createRule')} placement="bottom">
<div
className="univer-size-5"
<a
className="univer-size-5 univer-cursor-pointer"
onClick={handleCreate}
>
<IncreaseSingle />
</div>
</a>
</Tooltip>
{(ruleList.length && isHasAllRuleEditPermission)
? (
<Tooltip title={localeService.t('sheet.cf.panel.clear')} placement="bottom">
<div
className={clsx(styles.gap, 'univer-size-5')}
<a
className="univer-size-5 univer-cursor-pointer"
onClick={handleClear}
>
<DeleteSingle />
</div>
<DeleteSingle className="univer-text-red-500" />
</a>
</Tooltip>
)
: (
<div className={clsx(styles.gap, styles.disabled)}>
<DeleteSingle />
<div>
<DeleteSingle className="univer-text-gray-300" />
</div>
)}
</div>
</div>
<div ref={layoutContainerRef} className={styles.gridLayoutWrap}>
{layoutWidth
? (
<GridLayout
draggableHandle=".draggableHandle"
layout={layout}
cols={12}
rowHeight={60}
width={layoutWidth}
margin={[0, 10]}
onDragStop={handleDragStop}
onDragStart={handleDragStart}
>
{ruleListByPermissionCheck?.map((rule, index) => {
return (
<div key={`${rule.cfId}`}>
<div ref={layoutContainerRef}>
{layoutWidth > 0 && (
<GridLayout
className={`
[&_.react-grid-item]:univer-transition-none
[&_.react-grid-placeholder]:univer-rounded [&_.react-grid-placeholder]:!univer-bg-gray-200
`}
draggableHandle=".draggableHandle"
layout={layout}
cols={12}
rowHeight={60}
width={layoutWidth}
margin={[0, 10]}
onDragStop={handleDragStop}
onDragStart={handleDragStart}
>
{ruleListByPermissionCheck?.map((rule, index) => {
return (
<div key={`${rule.cfId}`}>
<div
className={clsx(`
univer-group univer-relative univer-flex univer-items-center
univer-justify-between univer-rounded univer-py-2 univer-pl-5 univer-pr-8
hover:univer-bg-gray-100
`, {
'univer-bg-gray-100': draggingId === index,
})}
onMouseMove={() => {
rule.ranges !== currentRuleRanges && currentRuleRangesSet(rule.ranges);
}}
onMouseLeave={() => currentRuleRangesSet([])}
onClick={() => {
onClick(rule);
}}
>
<div
className={clsx(styles.ruleItem, {
[styles.active]: draggingId === index,
})}
onMouseMove={() => {
rule.ranges !== currentRuleRanges && currentRuleRangesSet(rule.ranges);
}}
onMouseLeave={() => currentRuleRangesSet([])}
onClick={() => {
onClick(rule);
}}
className={clsx(`
univer-absolute univer-left-0 univer-hidden univer-size-5
univer-cursor-grab univer-items-center univer-justify-center
univer-rounded
group-hover:univer-flex
`, 'draggableHandle')}
onClick={(e) => e.stopPropagation()}
>
<div
className={clsx(styles.draggableHandle, 'draggableHandle')}
onClick={(e) => e.stopPropagation()}
>
<SequenceSingle />
<SequenceSingle />
</div>
<div
className={`
univer-min-w-0 univer-max-w-full univer-flex-shrink univer-overflow-hidden
`}
>
<div className="univer-text-sm univer-text-gray-900">
{getRuleDescribe(rule, localeService)}
</div>
<div className={styles.ruleDescribe}>
<div className={styles.ruleType}>
{getRuleDescribe(rule, localeService)}
</div>
<div className={styles.ruleRange}>
{rule.ranges.map((range) => serializeRange(range)).join(',')}
</div>
</div>
<div>
<Preview rule={rule.rule} />
</div>
<div
className={clsx(styles.deleteItem, {
[styles.active]: draggingId === index,
})}
onClick={(e) => {
e.stopPropagation();
handleDelete(rule);
currentRuleRangesSet([]);
}}
>
<DeleteSingle />
<div className="univer-text-xs univer-text-gray-400">
{rule.ranges.map((range) => serializeRange(range)).join(',')}
</div>
</div>
<div>
<Preview rule={rule.rule} />
</div>
<div
className={clsx(`
univer-absolute univer-right-1 univer-hidden univer-size-6
univer-cursor-pointer univer-items-center univer-justify-center
univer-rounded
group-hover:univer-flex
hover:univer-bg-gray-200
`, {
'univer-flex univer-items-center univer-justify-center': draggingId === index,
})}
onClick={(e) => {
e.stopPropagation();
handleDelete(rule);
currentRuleRangesSet([]);
}}
>
<DeleteSingle />
</div>
</div>
);
})}
</GridLayout>
)
: null}
</div>
);
})}
</GridLayout>
) }
</div>
</div>
);
@@ -1,9 +0,0 @@
.cf-preview {
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
min-width: 72px;
height: 20px;
font-size: 12px;
}
@@ -16,16 +16,16 @@
import type { IConditionalFormattingRuleConfig } from '@univerjs/sheets-conditional-formatting';
import { BooleanNumber, ColorKit } from '@univerjs/core';
import { clsx } from '@univerjs/design';
import { SlashSingle } from '@univerjs/icons';
import { CFRuleType, DEFAULT_BG_COLOR, DEFAULT_FONT_COLOR, defaultDataBarNativeColor, defaultDataBarPositiveColor, getColorScaleFromValue, iconMap } from '@univerjs/sheets-conditional-formatting';
import React, { useMemo } from 'react';
import styles from './index.module.less';
import { useMemo } from 'react';
export const Preview = (props: { rule?: IConditionalFormattingRuleConfig }) => {
const rule = props.rule;
if (!rule) {
return null;
}
if (!rule) return null;
const colorList = useMemo(() => {
if (rule.type === CFRuleType.colorScale) {
const config = rule.config.map((c, index) => ({ color: new ColorKit(c.color), value: index }));
@@ -35,6 +35,7 @@ export const Preview = (props: { rule?: IConditionalFormattingRuleConfig }) => {
}
return null;
}, [rule]);
const iconSet = useMemo(() => {
if (rule.type === CFRuleType.iconSet) {
return rule.config.map((item) => {
@@ -43,34 +44,53 @@ export const Preview = (props: { rule?: IConditionalFormattingRuleConfig }) => {
});
}
}, [rule]);
const previewClassName = `univer-pointer-events-none univer-flex univer-h-5 univer-min-w-[72px] univer-items-center
univer-justify-center univer-text-xs`;
switch (rule.type) {
case CFRuleType.dataBar:
{
const { isGradient } = rule.config;
const commonStyle = { width: '50%', height: '100%' };
const positiveColor = isGradient ? `linear-gradient(to right, ${rule.config.positiveColor || defaultDataBarPositiveColor}, rgb(255 255 255))` : rule.config.positiveColor;
const nativeColor = isGradient ? `linear-gradient(to right, rgb(255 255 255),${rule.config.nativeColor || defaultDataBarNativeColor})` : rule.config.nativeColor;
return (
<div className={styles.cfPreview}>
<div style={{ ...commonStyle, background: nativeColor, border: `1px solid ${rule.config.nativeColor || defaultDataBarNativeColor}` }} />
<div style={{ ...commonStyle, background: positiveColor, border: `1px solid ${rule.config.positiveColor || defaultDataBarPositiveColor}` }} />
<div className={previewClassName}>
<div
className="univer-h-full univer-w-1/2"
style={{
background: nativeColor,
border: `1px solid ${rule.config.nativeColor || defaultDataBarNativeColor}`,
}}
/>
<div
className="univer-h-full univer-w-1/2"
style={{
background: positiveColor,
border: `1px solid ${rule.config.positiveColor || defaultDataBarPositiveColor}`,
}}
/>
</div>
);
}
case CFRuleType.colorScale: {
return colorList && (
<div className={styles.cfPreview}>
<div className={previewClassName}>
{colorList.map((item, index) => (
<div key={index} style={{ width: `${100 / colorList.length}%`, height: '100%', background: item }} />
<div key={index} className="univer-h-full" style={{ width: `${100 / colorList.length}%`, background: item }} />
))}
</div>
);
}
case CFRuleType.iconSet: {
return iconSet && (
<div className={styles.cfPreview}>
{iconSet.map((base64, index) => (base64 ? <img style={{ height: '100%' }} key={index} src={base64} /> : <SlashSingle key={index} />))}
<div className={previewClassName}>
{iconSet.map((base64, index) => (
base64 ?
<img key={index} className="univer-h-full" src={base64} draggable={false} />
: <SlashSingle key={index} />))}
</div>
);
}
@@ -83,18 +103,22 @@ export const Preview = (props: { rule?: IConditionalFormattingRuleConfig }) => {
const bgColor = bg?.rgb ?? DEFAULT_BG_COLOR;
const fontColor = cl?.rgb ?? DEFAULT_FONT_COLOR;
const style = {
fontWeight: isBold ? 'bold' : undefined,
fontStyle: isItalic ? 'italic' : undefined,
textDecoration: `${isUnderline ? 'underline' : ''} ${isStrikethrough ? 'line-through' : ''}`.replace(/^ /, '') || undefined,
textDecoration: `${isUnderline ? 'underline' : ''} ${isStrikethrough ? 'line-through' : ''}`.replace(/^ /, '') ?? undefined,
backgroundColor: bgColor,
color: fontColor,
};
return (
<div style={style} className={styles.cfPreview}>
<div
className={clsx(previewClassName, {
'univer-font-bold': isBold,
'univer-italic': isItalic,
})}
style={style}
>
123
</div>
);
}
}
return null;
};
@@ -80,10 +80,10 @@
},
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"@univerjs/icons-svg": "^0.3.22",
"@univerjs/icons-svg": "^0.3.24",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -92,7 +92,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -90,7 +90,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -84,7 +84,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -98,7 +98,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -63,7 +63,7 @@
"@univerjs-infra/shared": "workspace:*",
"@univerjs/sheets": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -84,7 +84,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -79,7 +79,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -88,7 +88,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -97,7 +97,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -87,7 +87,7 @@
"@univerjs/docs": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -63,7 +63,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -100,7 +100,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -80,7 +80,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+7 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@univerjs/sheets-note-ui",
"version": "0.6.10",
"version": "0.7.0-beta.0",
"private": false,
"description": "Univer sheets note UI plugin",
"author": "DreamNum <developer@univer.ai>",
@@ -64,6 +64,7 @@
},
"dependencies": {
"@univerjs/core": "workspace:*",
"@univerjs/design": "workspace:*",
"@univerjs/engine-render": "workspace:*",
"@univerjs/icons": "^0.3.24",
"@univerjs/sheets": "workspace:*",
@@ -75,9 +76,10 @@
"devDependencies": {
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"less": "^4.1.3",
"typescript": "^5.4.3",
"vite": "^4.5.2",
"vitest": "^1.3.1"
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+2
View File
@@ -0,0 +1,2 @@
@tailwind components;
@tailwind utilities;
+2
View File
@@ -14,6 +14,8 @@
* limitations under the License.
*/
import './global.css';
export * from './plugin';
export * from './services/sheets-note-popup.service';
export * from './views/note';
+8 -6
View File
@@ -19,6 +19,7 @@ import type { ISheetNote } from '@univerjs/sheets-note';
import type { IPopup } from '@univerjs/ui';
import type { IUniverSheetsNoteUIPluginConfig } from '../plugin';
import { ICommandService, LocaleService } from '@univerjs/core';
import { clsx, scrollbarClassName } from '@univerjs/design';
import { SheetDeleteNoteCommand, SheetsNoteModel, SheetUpdateNoteCommand } from '@univerjs/sheets-note';
import { useConfigValue, useDebounceFn, useDependency } from '@univerjs/ui';
import { useEffect, useMemo, useRef, useState } from 'react';
@@ -111,16 +112,17 @@ export const SheetsNote = (props: { popup: IPopup<{ location: ISheetLocationBase
return (
<textarea
style={{ width: note.width, height: note.height }}
ref={textareaRef}
className={`
univer-note-textarea univer-resize-both univer-ml-[1px] univer-rounded univer-border univer-border-solid
univer-border-gray-200 univer-p-2 univer-shadow
data-u-comp="note-textarea"
className={clsx(`
univer-resize-both univer-ml-[1px] univer-rounded univer-border univer-border-solid univer-border-gray-200
univer-p-2 univer-shadow
focus:univer-outline-none
`}
`, scrollbarClassName)}
style={{ width: note.width, height: note.height }}
value={note.note}
onChange={handleNoteChange}
placeholder={localeService.t('note.placeholder')}
onChange={handleNoteChange}
/>
);
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@univerjs/sheets-note",
"version": "0.6.10",
"version": "0.7.0-beta.0",
"private": false,
"description": "Univer sheets note base plugin",
"author": "DreamNum <developer@univer.ai>",
@@ -77,7 +77,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+2 -2
View File
@@ -30,8 +30,8 @@ export class SheetsNotePlugin extends Plugin {
static override type = UniverInstanceType.UNIVER_SHEET;
constructor(
@Inject(Injector) protected override readonly _injector: Injector,
@IConfigService private readonly _configService: IConfigService
@IConfigService private readonly _configService: IConfigService,
@Inject(Injector) protected override readonly _injector: Injector
) {
super();
}
+1 -1
View File
@@ -87,7 +87,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -81,7 +81,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -84,7 +84,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -80,7 +80,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -90,7 +90,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -81,7 +81,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -84,7 +84,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -79,7 +79,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -100,7 +100,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
@@ -14,9 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import styles from './index.module.less';
import { ZoomSlider } from './ZoomSlider';
interface ICountBarProps {
@@ -26,7 +23,7 @@ interface ICountBarProps {
export function CountBar(props: ICountBarProps) {
return (
<section className={styles.countBar}>
<section className="univer-flex univer-flex-shrink-0 univer-justify-end">
<ZoomSlider />
</section>
);
@@ -16,15 +16,12 @@
import type { IScrollState } from './sheet-bar-tabs/utils/slide-tab-bar';
import { ICommandService, IPermissionService } from '@univerjs/core';
import { clsx } from '@univerjs/design';
import { IncreaseSingle, MoreSingle } from '@univerjs/icons';
import { InsertSheetCommand, WorkbookCreateSheetPermission, WorkbookEditablePermission } from '@univerjs/sheets';
import { useDependency, useObservable } from '@univerjs/ui';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useActiveWorkbook } from '../../components/hook';
import { ISheetBarService } from '../../services/sheet-bar/sheet-bar.service';
import styles from './index.module.less';
import { SheetBarButton } from './sheet-bar-button/SheetBarButton';
import { SheetBarMenu } from './sheet-bar-menu/SheetBarMenu';
import { SheetBarTabs } from './sheet-bar-tabs/SheetBarTabs';
@@ -78,8 +75,8 @@ export const SheetBar = () => {
};
return (
<div className={clsx(styles.sheetBar, 'univer-relative univer-flex univer-h-full univer-flex-1')}>
<div className={styles.sheetBarOptions}>
<div className="univer-relative univer-flex univer-h-full univer-min-w-0 univer-flex-1">
<div className="univer-flex univer-items-center univer-pl-2">
{/* Add sheet button */}
<SheetBarButton onClick={addSheet} disabled={!(workbookCreateSheetPermission?.value && workbookEditablePermission?.value)}>
<IncreaseSingle />
@@ -95,12 +92,13 @@ export const SheetBar = () => {
{(!leftScrollState || !rightScrollState) && (
<div
className={`
${styles.sheetBarOptions}
${styles.sheetBarOptionsDivider}
univer-relative univer-flex univer-items-center univer-px-2
after:univer-absolute after:univer-right-0 after:univer-top-1/2 after:univer-h-4 after:univer-w-px
after:-univer-translate-y-1/2 after:univer-bg-gray-200 after:univer-content-[""]
`}
>
<SheetBarButton disabled={leftScrollState} onClick={handleScrollLeft}>
<MoreSingle style={{ transform: 'rotateZ(180deg)' }} />
<MoreSingle className="univer-rotate-180" />
</SheetBarButton>
<SheetBarButton disabled={rightScrollState} onClick={handleScrollRight}>
<MoreSingle />
@@ -1,31 +0,0 @@
@sheet-bar-max-width: 1515px;
@status-bar-max-width: 332px;
@zoom-slider-width: 260px;
@margin-right: -4px;
.sheet-bar {
min-width: calc(100% - @zoom-slider-width - @status-bar-max-width);
max-width: calc(100% - @zoom-slider-width);
&-options {
display: flex;
flex-direction: row;
align-items: center;
margin: var(--margin-xxs);
transition: display 0.2s;
&-divider::after {
content: '';
display: block;
width: 1px;
height: 16px;
margin: 0 var(--margin-xs);
background-color: rgb(var(--grey-400));
}
}
}
@@ -56,7 +56,7 @@ export function RenderSheetFooter() {
{sheetBar && <SheetBar />}
{statisticBar && <StatusBar />}
{menus && footerMenus.length && (
<div className="univer-mr-2 univer-flex univer-gap-2">
<div className="univer-box-border univer-flex univer-gap-2 univer-px-2">
{footerMenus.map((item) => item.children?.map((child) => (
child?.item && (
<ToolbarItem
@@ -15,13 +15,11 @@
*/
import type { IFunctionNames } from '@univerjs/engine-formula';
import type { FC } from 'react';
import { LocaleService, numfmt } from '@univerjs/core';
import { MessageType, Tooltip } from '@univerjs/design';
import { FUNCTION_NAMES_MATH, FUNCTION_NAMES_STATISTICAL, FUNCTION_NAMES_TEXT } from '@univerjs/engine-formula';
import { IClipboardInterfaceService, IMessageService, useDependency } from '@univerjs/ui';
import React from 'react';
import styles from './index.module.less';
export interface IStatisticItem {
name: IFunctionNames;
@@ -52,7 +50,7 @@ interface IFunctionNameMap {
[key: string]: string;
}
export const CopyableStatisticItem: React.FC<IStatisticItem> = (item: IStatisticItem) => {
export const CopyableStatisticItem: FC<IStatisticItem> = (item: IStatisticItem) => {
const localeService = useDependency(LocaleService);
const messageService = useDependency(IMessageService);
const clipboardService = useDependency(IClipboardInterfaceService);
@@ -68,7 +66,14 @@ export const CopyableStatisticItem: React.FC<IStatisticItem> = (item: IStatistic
};
return (
<Tooltip title={localeService.t('statusbar.clickToCopy')} placement="top">
<div key={item.name} className={styles.statisticItem} onClick={copyToClipboard}>
<div
key={item.name}
className={`
univer-flex univer-max-w-24 univer-cursor-default univer-truncate univer-text-center univer-text-xs
univer-text-gray-400
`}
onClick={copyToClipboard}
>
<span>
{`${localeService.t(
functionDisplayNames?.[item.name as string] || (item.name as string)
@@ -15,17 +15,17 @@
*/
import type { Nullable } from '@univerjs/core';
import type { ComponentType } from 'react';
import type { IUniverSheetsUIConfig } from '../../controllers/config.schema';
import type { IStatusBarServiceStatus, StatusBarService } from '../../services/status-bar.service';
import type { IStatisticItem } from './CopyableStatisticItem';
import { debounce } from '@univerjs/core';
import { clsx } from '@univerjs/design';
import { useConfigValue, useDependency } from '@univerjs/ui';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { SHEETS_UI_PLUGIN_CONFIG_KEY } from '../../controllers/config.schema';
import { IStatusBarService } from '../../services/status-bar.service';
import { CopyableStatisticItem } from './CopyableStatisticItem';
import styles from './index.module.less';
const SINGLE_MODE_WIDTH = 800;
const ROW_COUNT_THRESHOLD = 3;
@@ -120,10 +120,10 @@ export const StatusBar = () => {
const useStatisticLayout = (
showList: IStatisticItem[],
rowCountThreshold: number,
CopyableStatisticItem: React.ComponentType<IStatisticItem>
CopyableStatisticItem: ComponentType<IStatisticItem>
) => {
if (!showStatistic) return null;
const renderContent = React.useMemo(() => {
const renderContent = useMemo(() => {
if (showList.length > rowCountThreshold) {
const doubleLineList = showList.reduce<IStatisticItem[][]>((acc, _, index) => {
if (index % 2 === 0) {
@@ -135,10 +135,7 @@ export const StatusBar = () => {
return (
<>
{doubleLineList.map((item, index) => (
<div
key={`stat-col-${index}`}
className={styles.statisticListColumn}
>
<div key={`stat-col-${index}`}>
{item[0] && (
<CopyableStatisticItem
key={item[0].name}
@@ -177,12 +174,16 @@ export const StatusBar = () => {
return (
show && (
<div
className={clsx(styles.statusBar, {
[styles.singleMode]: isSingle,
className={clsx(`
univer-relative univer-box-border univer-flex univer-items-center univer-px-2
after:univer-absolute after:univer-right-0 after:univer-top-1/2 after:univer-block after:univer-h-4
after:univer-w-px after:-univer-translate-y-1/2 after:univer-bg-gray-200 after:univer-content-[""]
`, {
'univer-max-w-32': isSingle,
'univer-max-w-80': !isSingle,
})}
>
<div className="univer-flex">{renderContent}</div>
<div className={styles.statusBarDiv} />
<div className="univer-flex univer-gap-x-2">{renderContent}</div>
</div>
)
);
@@ -1,93 +0,0 @@
@statistic-menu-value-width: 55px;
.status-bar {
display: flex;
align-items: center;
max-width: 332px;
&.single-mode {
max-width: 136px;
}
}
.status-bar-div {
width: 1px;
height: 16px;
margin-left: 10px;
background: rgb(var(--grey-400, #ccc));
}
.statistic {
&-list-column &-item {
font-size: 12px;
line-height: 140%;
color: rgb(var(--grey-500));
}
&-item {
cursor: default;
overflow: hidden;
display: flex;
justify-content: flex-start;
max-width: 106px;
margin-right: 8px;
font-size: var(--font-size-xxs);
font-weight: 400;
font-style: normal;
line-height: 20px; /* 181.818% */
color: rgb(var(--grey-900));
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
&:hover {
color: rgb(var(--color-black));
}
}
&-picker {
display: grid;
gap: var(--margin-sm);
align-items: center;
box-sizing: border-box;
width: 196px;
padding: var(--padding-base);
font-size: var(--font-size-xs);
background-color: rgb(var(--color-white));
border: 1px solid rgb(var(--border-color));
border-radius: var(--border-radius-lg);
box-shadow: var(--box-shadow-lg);
}
&-picker-item {
display: flex;
align-items: center;
justify-content: flex-start;
}
&-more {
transform: rotate(90deg);
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
font-size: 12px;
color: rgb(var(--grey-600, #e8e8e8));
border-radius: 4px;
&:hover {
background: rgb(var(--grey-300, #e8e8e8));
}
}
}
+1 -1
View File
@@ -97,7 +97,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -90,7 +90,7 @@
"@univerjs/network": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -85,7 +85,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -64,7 +64,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -60,7 +60,7 @@
"devDependencies": {
"@univerjs-infra/shared": "workspace:*",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -81,7 +81,7 @@
"rxjs": "^7.8.1",
"tailwindcss": "^3.4.17",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -66,7 +66,7 @@
"@univerjs-infra/shared": "workspace:*",
"rxjs": "^7.8.1",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2"
}
}
+1 -1
View File
@@ -100,7 +100,7 @@
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"typescript": "^5.8.3",
"vite": "^6.3.3",
"vite": "^6.3.4",
"vitest": "^3.1.2",
"vue": "^3.5.13"
}

Some files were not shown because too many files have changed in this diff Show More