snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { LocaleService } from '@univerjs/core';
|
||||
import { InputNumber, Select } from '@univerjs/design';
|
||||
import { getCurrencyType, getDecimalFromPattern, setPatternDecimal } from '@univerjs/sheets-numfmt';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { UserHabitCurrencyContext } from '../../controllers/user-habit.controller';
|
||||
|
||||
export const isAccountingPanel = (pattern: string) => {
|
||||
const type = getCurrencyType(pattern);
|
||||
return !!type && pattern.startsWith('_(');
|
||||
};
|
||||
|
||||
export function AccountingPanel(props: IBusinessComponentProps) {
|
||||
const { defaultPattern, onActionChange, onChange } = props;
|
||||
|
||||
const [decimal, setDecimal] = useState(() => getDecimalFromPattern(defaultPattern || '', 2));
|
||||
const userHabitCurrency = useContext(UserHabitCurrencyContext);
|
||||
const [suffix, setSuffix] = useState(() => getCurrencyType(defaultPattern) || userHabitCurrency[0]);
|
||||
const options = useMemo(() => userHabitCurrency.map((key) => ({ label: key, value: key })), []);
|
||||
|
||||
const localeService = useDependency(LocaleService);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal));
|
||||
}, [decimal, onActionChange, suffix]);
|
||||
|
||||
const handleSelect = (v: string) => {
|
||||
setSuffix(v);
|
||||
onChange(setPatternDecimal(`_("${v}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal));
|
||||
};
|
||||
|
||||
const handleDecimalChange = (v: number | null) => {
|
||||
const decimal = v || 0;
|
||||
setDecimal(decimal);
|
||||
onChange(setPatternDecimal(`_("${suffix}"* #,##0${decimal > 0 ? '.0' : ''}_)`, decimal));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="univer-mt-4 univer-flex univer-justify-between">
|
||||
<div className="option">
|
||||
<div className="univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.decimalLength')}
|
||||
</div>
|
||||
|
||||
<div className="univer-mt-2 univer-w-32">
|
||||
<InputNumber
|
||||
value={decimal}
|
||||
step={1}
|
||||
precision={0}
|
||||
max={20}
|
||||
min={0}
|
||||
onChange={handleDecimalChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="option">
|
||||
<div className="univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.currencyType')}
|
||||
</div>
|
||||
|
||||
<div className="univer-mt-2 univer-w-36">
|
||||
<Select
|
||||
options={options}
|
||||
value={suffix}
|
||||
onChange={handleSelect}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.accountingDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
122
packages/sheets-numfmt-ui/src/views/components/Currency.tsx
Normal file
122
packages/sheets-numfmt-ui/src/views/components/Currency.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { isPatternEqualWithoutDecimal, LocaleService } from '@univerjs/core';
|
||||
import { InputNumber, Select, SelectList } from '@univerjs/design';
|
||||
import {
|
||||
getCurrencyFormatOptions,
|
||||
getCurrencyType,
|
||||
getDecimalFromPattern,
|
||||
setPatternDecimal,
|
||||
} from '@univerjs/sheets-numfmt';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { UserHabitCurrencyContext } from '../../controllers/user-habit.controller';
|
||||
|
||||
export const isCurrencyPanel = (pattern: string) => {
|
||||
const type = getCurrencyType(pattern);
|
||||
return !!type && !pattern.startsWith('_(');
|
||||
};
|
||||
|
||||
export function CurrencyPanel(props: IBusinessComponentProps) {
|
||||
const { onActionChange, onChange: onValueChange } = props;
|
||||
const localeService = useDependency(LocaleService);
|
||||
const userHabitCurrency = useContext(UserHabitCurrencyContext);
|
||||
const [suffix, setSuffix] = useState(() => getCurrencyType(props.defaultPattern) || userHabitCurrency[0]);
|
||||
const [decimal, setDecimal] = useState(() => getDecimalFromPattern(props.defaultPattern || '', 2));
|
||||
const [pattern, setPattern] = useState(() => {
|
||||
const negativeOptions = getCurrencyFormatOptions(suffix);
|
||||
const pattern =
|
||||
negativeOptions.find((item) => isPatternEqualWithoutDecimal(item.value, props.defaultPattern))?.value ||
|
||||
negativeOptions[0].value;
|
||||
return pattern;
|
||||
});
|
||||
|
||||
const negativeOptions = useMemo(() => getCurrencyFormatOptions(suffix), [suffix]);
|
||||
const options = useMemo(() => userHabitCurrency.map((key) => ({ label: key, value: key })), [userHabitCurrency]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => setPatternDecimal(pattern, decimal));
|
||||
}, [decimal, onActionChange, pattern]);
|
||||
|
||||
const onSelect = (value: string) => {
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
setSuffix(value);
|
||||
const pattern = getCurrencyFormatOptions(value)[0].value;
|
||||
setPattern(pattern);
|
||||
onValueChange(setPatternDecimal(pattern, decimal));
|
||||
};
|
||||
|
||||
const onChange = (value: any) => {
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
setPattern(value);
|
||||
onValueChange(setPatternDecimal(value, decimal));
|
||||
};
|
||||
|
||||
const onDecimalChange = (v: number | null) => {
|
||||
setDecimal(v || 0);
|
||||
onValueChange(setPatternDecimal(pattern, v || 0));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="univer-mt-4 univer-flex univer-justify-between">
|
||||
<div className="option">
|
||||
<div className="univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.decimalLength')}
|
||||
</div>
|
||||
<div className="univer-mt-2 univer-w-32">
|
||||
<InputNumber
|
||||
value={decimal}
|
||||
max={20}
|
||||
min={0}
|
||||
onChange={onDecimalChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="option">
|
||||
<div className="univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.currencyType')}
|
||||
</div>
|
||||
<div className="univer-mt-2 univer-w-36">
|
||||
<Select
|
||||
value={suffix}
|
||||
options={options}
|
||||
onChange={onSelect}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="label univer-mt-4">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.negType')}
|
||||
</div>
|
||||
|
||||
<div className="univer-mt-2">
|
||||
<SelectList value={pattern} options={negativeOptions} onChange={onChange} />
|
||||
</div>
|
||||
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.currencyDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
126
packages/sheets-numfmt-ui/src/views/components/CustomFormat.tsx
Normal file
126
packages/sheets-numfmt-ui/src/views/components/CustomFormat.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { ILocalStorageService, LocaleService } from '@univerjs/core';
|
||||
import { borderClassName, clsx, Input } from '@univerjs/design';
|
||||
import { CheckMarkIcon } from '@univerjs/icons';
|
||||
import { CURRENCYFORMAT, DATEFMTLISG, NUMBERFORMAT } from '@univerjs/sheets-numfmt';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { UserHabitController } from '../../controllers/user-habit.controller';
|
||||
|
||||
const key = 'customFormat';
|
||||
const historyPatternKey = 'numfmt_custom_pattern';
|
||||
|
||||
export function CustomFormat(props: IBusinessComponentProps) {
|
||||
const { defaultPattern, onActionChange, onChange } = props;
|
||||
const userHabitController = useDependency(UserHabitController);
|
||||
const localStorageService = useDependency(ILocalStorageService);
|
||||
const localeService = useDependency(LocaleService);
|
||||
|
||||
const [pattern, setPattern] = useState(defaultPattern);
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => {
|
||||
userHabitController.markHabit(key, pattern);
|
||||
localStorageService.getItem<string[]>(historyPatternKey).then((list = []) => {
|
||||
const _list = [...new Set([pattern, ...(list || [])])].splice(0, 10).filter((e) => !!e);
|
||||
localStorageService.setItem(historyPatternKey, _list);
|
||||
});
|
||||
return pattern;
|
||||
});
|
||||
}, [localStorageService, onActionChange, pattern, userHabitController]);
|
||||
const [options, setOptions] = useState<(string | number)[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
void localStorageService.getItem<string[]>(historyPatternKey).then((historyList) => {
|
||||
const list = [
|
||||
...CURRENCYFORMAT.map((item) => item.suffix('$')),
|
||||
...DATEFMTLISG.map((item) => item.suffix),
|
||||
...NUMBERFORMAT.map((item) => item.suffix),
|
||||
...(historyList ?? []),
|
||||
];
|
||||
return userHabitController.addHabit(key, []).then(() => userHabitController.getHabit(key, list));
|
||||
}).then((list) => {
|
||||
if (!cancelled) {
|
||||
setOptions([...new Set(list)]);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [localStorageService, userHabitController]);
|
||||
|
||||
const handleClick = (p: string) => {
|
||||
setPattern(p);
|
||||
onChange(p);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
onChange(pattern);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.customFormat')}
|
||||
</div>
|
||||
<Input
|
||||
placeholder={localeService.t<LocaleKey>('sheets-numfmt-ui.customFormat')}
|
||||
onBlur={handleBlur}
|
||||
value={pattern}
|
||||
onChange={setPattern}
|
||||
className="univer-mt-2 univer-w-full"
|
||||
/>
|
||||
<div
|
||||
className={clsx(
|
||||
'univer-mt-2 univer-max-h-[400px] univer-overflow-auto univer-rounded-lg univer-p-2',
|
||||
borderClassName
|
||||
)}
|
||||
>
|
||||
{options.map((p) => (
|
||||
<div
|
||||
key={p}
|
||||
onClick={() => handleClick(p as string)}
|
||||
className={`
|
||||
univer-flex univer-cursor-pointer univer-items-center univer-gap-1.5 univer-py-1.5
|
||||
univer-text-sm
|
||||
`}
|
||||
>
|
||||
<div className="univer-flex univer-w-4 univer-items-center univer-text-primary-600">
|
||||
{pattern === p && <CheckMarkIcon />}
|
||||
</div>
|
||||
<div>
|
||||
{p}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
univer-mt-3 univer-text-sm univer-text-gray-600
|
||||
dark:!univer-text-gray-200
|
||||
`}
|
||||
>
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.customFormatDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
80
packages/sheets-numfmt-ui/src/views/components/Date.tsx
Normal file
80
packages/sheets-numfmt-ui/src/views/components/Date.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { LocaleService, numfmt } from '@univerjs/core';
|
||||
import { SelectList } from '@univerjs/design';
|
||||
import { getDateFormatOptions } from '@univerjs/sheets-numfmt';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
export const isDatePanel = (pattern: string) => {
|
||||
const info = numfmt.getFormatInfo(pattern);
|
||||
return (
|
||||
getDateFormatOptions()
|
||||
.map((item) => item.value)
|
||||
.includes(pattern) || ['date', 'datetime', 'time'].includes(info.type)
|
||||
);
|
||||
};
|
||||
|
||||
export function DatePanel(props: IBusinessComponentProps) {
|
||||
const { onActionChange, onChange, defaultPattern } = props;
|
||||
|
||||
const options = useMemo(getDateFormatOptions, []);
|
||||
const localeService = useDependency(LocaleService);
|
||||
|
||||
const [suffix, setSuffix] = useState(() => {
|
||||
if (defaultPattern) {
|
||||
const item = options.find((item) => item.value === defaultPattern);
|
||||
if (item) {
|
||||
return item.value;
|
||||
}
|
||||
}
|
||||
return options[0].value;
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => suffix);
|
||||
}, [onActionChange, suffix]);
|
||||
|
||||
const handleChange = (v: any) => {
|
||||
if (v === undefined) {
|
||||
return;
|
||||
}
|
||||
setSuffix(v);
|
||||
onChange(v);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.dateType')}
|
||||
</div>
|
||||
<div className="univer-mt-2">
|
||||
<SelectList value={suffix} options={options} onChange={handleChange} />
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
univer-mt-3.5 univer-text-sm/5 univer-text-gray-600
|
||||
dark:!univer-text-gray-200
|
||||
`}
|
||||
>
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.dateDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
45
packages/sheets-numfmt-ui/src/views/components/General.tsx
Normal file
45
packages/sheets-numfmt-ui/src/views/components/General.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { LocaleService } from '@univerjs/core';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
export const isGeneralPanel = (pattern: string) => !pattern;
|
||||
|
||||
export function GeneralPanel(props: IBusinessComponentProps) {
|
||||
const localeService = useDependency(LocaleService);
|
||||
const { onActionChange } = props;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => '');
|
||||
}, [onActionChange]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className={`
|
||||
univer-mt-3.5 univer-text-sm/5 univer-text-gray-600
|
||||
dark:!univer-text-gray-200
|
||||
`}
|
||||
>
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.generalDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { FormatType } from '@univerjs/sheets';
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import { ICommandService, LocaleService, Range, RegionService } from '@univerjs/core';
|
||||
import { Separator } from '@univerjs/design';
|
||||
import { SheetsSelectionsService } from '@univerjs/sheets';
|
||||
import {
|
||||
getCurrencySymbolByLocale,
|
||||
getPatternPreview,
|
||||
getPatternType,
|
||||
SetNumfmtCommand,
|
||||
SheetsNumfmtCellContentController,
|
||||
} from '@univerjs/sheets-numfmt';
|
||||
import { ILayoutService, useDependency, useObservable } from '@univerjs/ui';
|
||||
import { useMemo } from 'react';
|
||||
import { OpenNumfmtPanelOperator } from '../../commands/operations/open.numfmt.panel.operation';
|
||||
import { MENU_OPTIONS } from '../../menu/number-format-options';
|
||||
|
||||
export const MORE_NUMFMT_TYPE_KEY = 'sheets-numfmt-ui.moreNumfmtType';
|
||||
export const OPTIONS_KEY = 'sheets-numfmt-ui.moreNumfmtType.options';
|
||||
|
||||
export function MoreNumfmtType(props: { value?: string }) {
|
||||
const { value } = props;
|
||||
const localeService = useDependency(LocaleService);
|
||||
const text = value ?? localeService.t<LocaleKey>('sheets-numfmt-ui.general');
|
||||
|
||||
return <span className="univer-text-sm">{text}</span>;
|
||||
};
|
||||
|
||||
export function Options() {
|
||||
const commandService = useDependency(ICommandService);
|
||||
const localeService = useDependency(LocaleService);
|
||||
const regionService = useDependency(RegionService);
|
||||
const layoutService = useDependency(ILayoutService);
|
||||
const sheetsNumfmtCellContentController = useDependency(SheetsNumfmtCellContentController);
|
||||
const direction = useObservable(localeService.direction$, localeService.getDirection());
|
||||
const region = useObservable(regionService.currentRegion$, regionService.getCurrentRegion());
|
||||
|
||||
const selectionManagerService = useDependency(SheetsSelectionsService);
|
||||
const setNumfmt = (pattern: string | null) => {
|
||||
const selection = selectionManagerService.getCurrentLastSelection();
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selection.range;
|
||||
const values: Array<{ row: number; col: number; pattern?: string; type?: FormatType }> = [];
|
||||
Range.foreach(range, (row, col) => {
|
||||
if (pattern) {
|
||||
values.push({ row, col, pattern, type: getPatternType(pattern) });
|
||||
} else {
|
||||
values.push({ row, col });
|
||||
}
|
||||
});
|
||||
commandService.executeCommand(SetNumfmtCommand.id, { values });
|
||||
|
||||
layoutService.focus();
|
||||
};
|
||||
|
||||
const menuOptions = useMemo(() => {
|
||||
const currencySymbol = getCurrencySymbolByLocale(region);
|
||||
return MENU_OPTIONS(currencySymbol);
|
||||
}, [region]);
|
||||
|
||||
const handleClick = (index: number) => {
|
||||
if (index === 0) {
|
||||
setNumfmt(null);
|
||||
} else if (index === menuOptions.length - 1) {
|
||||
// CATUION: This is a command, not a menu item
|
||||
commandService.executeCommand(OpenNumfmtPanelOperator.id);
|
||||
layoutService.focus();
|
||||
} else {
|
||||
const item = menuOptions[index] as { pattern: string };
|
||||
item.pattern && setNumfmt(item.pattern);
|
||||
}
|
||||
};
|
||||
|
||||
const defaultValue = 1220;
|
||||
|
||||
return (
|
||||
<div dir={direction} className="univer-grid univer-gap-1 univer-p-1.5">
|
||||
{menuOptions.map((item, index) => {
|
||||
if (item === '|') {
|
||||
return <Separator key={index} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`
|
||||
univer-flex univer-h-7 univer-cursor-default univer-items-center univer-justify-between
|
||||
univer-gap-6 univer-rounded univer-px-2 univer-text-sm
|
||||
hover:univer-bg-gray-100
|
||||
dark:hover:!univer-bg-gray-700
|
||||
`}
|
||||
onClick={() => handleClick(index)}
|
||||
>
|
||||
<span>{localeService.t<LocaleKey>(item.label)}</span>
|
||||
|
||||
<span
|
||||
className={`
|
||||
univer-text-xs univer-text-gray-500
|
||||
dark:!univer-text-gray-400
|
||||
`}
|
||||
>
|
||||
{item.pattern ? getPatternPreview(item.pattern || '', defaultValue, sheetsNumfmtCellContentController.locale).result.trim() : ''}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { LocaleKey } from '../../locale/types';
|
||||
import type { IBusinessComponentProps } from './interface';
|
||||
import { isPatternEqualWithoutDecimal, LocaleService } from '@univerjs/core';
|
||||
import { InputNumber, SelectList } from '@univerjs/design';
|
||||
import {
|
||||
getDecimalFromPattern,
|
||||
getNumberFormatOptions,
|
||||
isPatternHasDecimal,
|
||||
setPatternDecimal,
|
||||
} from '@univerjs/sheets-numfmt';
|
||||
import { useDependency } from '@univerjs/ui';
|
||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
export const isThousandthPercentilePanel = (pattern: string) =>
|
||||
getNumberFormatOptions().some((item) => isPatternEqualWithoutDecimal(item.value, pattern));
|
||||
|
||||
export function ThousandthPercentilePanel(props: IBusinessComponentProps) {
|
||||
const { onActionChange, onChange } = props;
|
||||
const localeService = useDependency(LocaleService);
|
||||
|
||||
const options = useMemo(getNumberFormatOptions, []);
|
||||
const [decimal, setDecimal] = useState(() => getDecimalFromPattern(props.defaultPattern || '', 0));
|
||||
|
||||
const [suffix, setSuffix] = useState(() => {
|
||||
const item = options.find((item) => isPatternEqualWithoutDecimal(item.value, props.defaultPattern || ''));
|
||||
return item?.value || options[0].value;
|
||||
});
|
||||
|
||||
const pattern = useMemo(() => setPatternDecimal(suffix, Number(decimal || 0)), [suffix, decimal]);
|
||||
|
||||
const isInputDisable = !isPatternHasDecimal(suffix);
|
||||
|
||||
const handleDecimalChange = (decimal: number | null) => {
|
||||
setDecimal(decimal || 0);
|
||||
onChange(setPatternDecimal(suffix, Number(decimal || 0)));
|
||||
};
|
||||
const handleClick = (v: any) => {
|
||||
if (v === undefined) {
|
||||
return;
|
||||
}
|
||||
setDecimal(getDecimalFromPattern(v, 0));
|
||||
setSuffix(v);
|
||||
onChange(v);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
onActionChange(() => pattern);
|
||||
}, [onActionChange, pattern]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.decimalLength')}
|
||||
</div>
|
||||
<div className="univer-mt-2">
|
||||
<InputNumber
|
||||
disabled={isInputDisable}
|
||||
value={decimal}
|
||||
max={20}
|
||||
min={0}
|
||||
onChange={handleDecimalChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="univer-mt-4 univer-text-sm univer-text-gray-400">
|
||||
{' '}
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.negType')}
|
||||
</div>
|
||||
<div className="univer-mt-2">
|
||||
<SelectList onChange={handleClick} options={options} value={suffix} />
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
univer-mt-3.5 univer-text-sm/5 univer-text-gray-600
|
||||
dark:!univer-text-gray-200
|
||||
`}
|
||||
>
|
||||
{localeService.t<LocaleKey>('sheets-numfmt-ui.thousandthPercentileDes')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
22
packages/sheets-numfmt-ui/src/views/components/interface.ts
Normal file
22
packages/sheets-numfmt-ui/src/views/components/interface.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 interface IBusinessComponentProps {
|
||||
onChange: (result: string) => void;
|
||||
onActionChange: (action: () => string | null) => void;
|
||||
defaultValue: number;
|
||||
defaultPattern: string;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import type { Dependency } from '@univerjs/core';
|
||||
import type { ISheetNumfmtPanelProps } from '../../SheetNumfmtPanel';
|
||||
import { LocaleService, LocaleType } from '@univerjs/core';
|
||||
import { RediContext } from '@univerjs/ui';
|
||||
import { useContext, useState } from 'react';
|
||||
import { UserHabitController } from '../../../controllers/user-habit.controller';
|
||||
import enUS from '../../../locale/en-US';
|
||||
import ruRU from '../../../locale/ru-RU';
|
||||
import zhCN from '../../../locale/zh-CN';
|
||||
import { SheetNumfmtPanel } from '../../SheetNumfmtPanel';
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'numfmt',
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const NumfmtPanel: StoryObj<ISheetNumfmtPanelProps> = {
|
||||
render() {
|
||||
const { injector } = useContext(RediContext);
|
||||
|
||||
const [inject] = useState(() => {
|
||||
const deps: Dependency[] = [
|
||||
[UserHabitController],
|
||||
];
|
||||
|
||||
injector?.get(LocaleService).load({
|
||||
[LocaleType.EN_US]: enUS,
|
||||
[LocaleType.ZH_CN]: zhCN,
|
||||
[LocaleType.RU_RU]: ruRU,
|
||||
});
|
||||
|
||||
deps.forEach((dependency) => injector?.add(dependency));
|
||||
|
||||
return injector;
|
||||
});
|
||||
|
||||
return (
|
||||
<RediContext.Provider value={{ injector: inject }}>
|
||||
<div className="univer-w-[340px]">
|
||||
<SheetNumfmtPanel
|
||||
value={{ defaultPattern: '', defaultValue: 123123, row: 2, col: 3 }}
|
||||
onChange={(_pattern) => {
|
||||
// empty
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</RediContext.Provider>
|
||||
);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user