diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index f7a4af35f..4280ad7ce 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup node uses: actions/setup-node@v3 @@ -22,7 +22,7 @@ jobs: cache: yarn - name: Cache yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} @@ -38,7 +38,7 @@ jobs: cp yarn.lock package-temp-dir - name: Cache node_modules id: node_modules_cache_id - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -51,7 +51,7 @@ jobs: runs-on: ubuntu-latest needs: [setup] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup node uses: actions/setup-node@v3 @@ -59,13 +59,13 @@ jobs: node-version: 14.x - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8d3f03139..888bbeb50 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup node uses: actions/setup-node@v3 @@ -24,7 +24,7 @@ jobs: cache: yarn - name: Cache yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} @@ -40,7 +40,7 @@ jobs: cp yarn.lock package-temp-dir - name: Cache node_modules id: node_modules_cache_id - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -53,16 +53,16 @@ jobs: needs: [setup] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -74,16 +74,16 @@ jobs: needs: [setup] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -95,16 +95,16 @@ jobs: needs: [setup] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -116,16 +116,16 @@ jobs: needs: [setup] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} @@ -137,16 +137,16 @@ jobs: runs-on: ubuntu-latest needs: [setup] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Restore cache from yarn.lock - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: package-temp-dir key: lock-${{ github.sha }} - name: Restore cache from node_modules - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: node_modules key: node_modules-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/package-temp-dir/yarn.lock') }} diff --git a/.prettierignore b/.prettierignore index 5c43558d8..24c2fd788 100644 --- a/.prettierignore +++ b/.prettierignore @@ -11,6 +11,3 @@ package-lock.json dist/ esm/ lib/ - -# 特殊的 -src/components/mxGraph/factory.tsx diff --git a/.yarnrc b/.yarnrc index cbdd124a4..57f8c2eb2 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,2 @@ registry "https://registry.yarnpkg.com" -sass_binary_site "https://npm.taobao.org/mirrors/node-sass/" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1e7ae21..41e745181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,48 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [3.0.10](https://github.com/DTStack/dt-react-component/compare/v3.0.9...v3.0.10) (2023-09-13) + + +### Features + +* add afterClose for ModalWithform ([#357](https://github.com/DTStack/dt-react-component/issues/357)) ([b2a5786](https://github.com/DTStack/dt-react-component/commit/b2a5786cac3fa5768729da3f0856586025d6ff97)) +* add spreadSheet columnSort and columnTypes ([#372](https://github.com/DTStack/dt-react-component/issues/372)) ([f4abb1c](https://github.com/DTStack/dt-react-component/commit/f4abb1c3a0d29a372d7858ac493f848275cb18dc)) +* spreadSheet comp support extra options from outside ([#365](https://github.com/DTStack/dt-react-component/issues/365)) ([5018071](https://github.com/DTStack/dt-react-component/commit/5018071af41c5ffe5c6b158d9f09ca3ba0b3586f)) + +### [3.0.9](https://github.com/DTStack/dt-react-component/compare/v3.0.7...v3.0.9) (2023-06-25) + + +### Features + +* add copyWithHeader item to spreadSheet context menu ([#287](https://github.com/DTStack/dt-react-component/issues/287)) ([ee6ee5c](https://github.com/DTStack/dt-react-component/commit/ee6ee5c5bfcf6f95007f4a376709d3a04d17f714)) +* update blockHeader margin-bottom ([#281](https://github.com/DTStack/dt-react-component/issues/281)) ([2962911](https://github.com/DTStack/dt-react-component/commit/29629111840bd68a142b4f49e083ba2a23e97355)) + + +### Bug Fixes + +* [#82926](https://github.com/DTStack/dt-react-component/issues/82926) handsontable trimWhitespace should be false ([#358](https://github.com/DTStack/dt-react-component/issues/358)) ([24d145d](https://github.com/DTStack/dt-react-component/commit/24d145da94cc6820c819eff8fe227a1c616411a5)) +* fix ModalProps for modalWithForm ([#283](https://github.com/DTStack/dt-react-component/issues/283)) ([f0c813a](https://github.com/DTStack/dt-react-component/commit/f0c813a306dc2cadd495ce15cae7b4328b155ad4)) + +### [3.0.8](https://github.com/DTStack/dt-react-component/compare/v3.0.7...v3.0.8) (2023-01-11) + + +### Features + +* update blockHeader margin-bottom ([#281](https://github.com/DTStack/dt-react-component/issues/281)) ([2962911](https://github.com/DTStack/dt-react-component/commit/29629111840bd68a142b4f49e083ba2a23e97355)) + + +### Bug Fixes + +* fix ModalProps for modalWithForm ([#283](https://github.com/DTStack/dt-react-component/issues/283)) ([f0c813a](https://github.com/DTStack/dt-react-component/commit/f0c813a306dc2cadd495ce15cae7b4328b155ad4)) + +### [3.0.7](https://github.com/DTStack/dt-react-component/compare/v3.0.6...v3.0.7) (2022-12-16) + + +### Bug Fixes + +* [#278](https://github.com/DTStack/dt-react-component/issues/278) use handsontable lower version ([#279](https://github.com/DTStack/dt-react-component/issues/279)) ([ee59dd9](https://github.com/DTStack/dt-react-component/commit/ee59dd93aa4578be9f4353b9deb85a4d6cd034e4)) + ### [3.0.6](https://github.com/DTStack/dt-react-component/compare/v3.0.5...v3.0.6) (2022-12-07) diff --git a/README-zh_CN.md b/README-zh_CN.md index 9add186ed..e19f4d950 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -10,9 +10,6 @@ [English](./README.md) | 简体中文 -## 文档 -- [v3.x](https://dtstack.github.io/dt-react-component/) -- [v2.x](https://liuxy0551.github.io/dt-react-component/) 基于 [ant-design](https://github.com/ant-design/ant-design) 的 React UI 组件库。 主要用于中,后台产品。我们的目标是**满足更具体的业务场景组件**。 当然,我们也有基于原生 javascript 实现的业务组件,例如**ContextMenu**,**KeyEventListener**等。 diff --git a/README.md b/README.md index 6e02379e6..15ecda884 100755 --- a/README.md +++ b/README.md @@ -10,9 +10,6 @@ English | [简体中文](./README-zh_CN.md) -## Docs -- [v3.x](https://dtstack.github.io/dt-react-component/) -- [v2.x](https://liuxy0551.github.io/dt-react-component/) React UI component library based on [ant-design](https://github.com/ant-design/ant-design). Mainly used for middle and back-end products. Our goal is to **meet more specific and more specific business scenario components**. Of course, we also have excellent business components based on native javascript, such as **ContextMenu**, **KeyEventListener** and so on. diff --git a/jest.config.js b/jest.config.js index 0391a1d18..ef0f4228d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,7 +5,7 @@ module.exports = { transformIgnorePatterns: ['/node_modules/', 'lib', 'dist'], testPathIgnorePatterns: ['/node_modules/'], transform: { - '^.+\\.[jt]s?(x)$': 'babel-jest', + '^.+\\.(ts|tsx|js|jsx)$': 'babel-jest', }, testMatch: [ '**/__tests__/**/(*.)+(spec|test).[jt]s?(x)', diff --git a/mock/mock.js b/mock/mock.js index 38b08af1d..9dc5fc1e4 100644 --- a/mock/mock.js +++ b/mock/mock.js @@ -1 +1 @@ -module.exports = ""; +module.exports = ''; diff --git a/package.json b/package.json index cdc554a9f..aafcfc971 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dt-react-component", - "version": "3.0.6", + "version": "3.0.10", "description": "react-component", "repository": "https://github.com/DTStack/dt-react-component", "sideEffects": [ @@ -29,14 +29,14 @@ "check-types": "tsc --skipLibCheck", "test": "jest --coverage --env=jest-environment-jsdom-sixteen", "test:update": "npm run test -u", - "prettier": "npx prettier --check './**/*.{js,jsx,json,ts,tsx}'", - "prettier:fix": "npx prettier --write './**/*.{js,jsx,json,ts,tsx}'", + "prettier": "npx prettier --check '**/*.{js,jsx,json,ts,tsx}'", + "prettier:fix": "npx prettier --write '**/*.{js,jsx,json,ts,tsx}'", "eslint": "npx eslint .", "eslint:fix": "npx eslint . --fix", "lint-doc": "node ./node_modules/lint-md/bin ./*.md src/stories/markdown/*.md", "lint-doc:fix": "npx eslint './src/**/*.tsx' --fix && lint-md ./*.md src/stories/markdown/*.md --fix", - "stylelint": "npx stylelint './**/*.{less,css,scss}'", - "stylelint:fix": "npx stylelint './**/*.{less,css,scss}' --fix" + "stylelint": "npx stylelint '**/*.{less,css,scss}'", + "stylelint:fix": "npx stylelint '**/*.{less,css,scss}' --fix" }, "keywords": [ "react", @@ -95,9 +95,9 @@ "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", "@types/history": "^4.7.0", - "@types/jest": "^26.0.9", + "@types/jest": "^24.9.1", "@types/lodash": "4.14.118", - "@types/react": "18.0.17", + "@types/react": "^16.14.28", "@types/react-router": "^3.0.4", "@types/react-slick": "^0.23.4", "@types/storybook__addon-knobs": "^5.0.3", @@ -133,13 +133,14 @@ "increase-memory-limit": "^1.0.7", "jest": "^24.9.0", "jest-environment-jsdom-sixteen": "^2.0.0", - "ko-lint-config": "^2.2.15", + "ko-lint-config": "2.2.19", "less": "^3.9.0", "less-loader": "^5.0.0", "lint-md": "^0.1.1", "merge-stream": "^2.0.0", "node-sass": "4.14.1", - "react": "16.13.0", + "prettier": "2.7.1", + "react": "16.13.1", "react-docgen-typescript-loader": "^3.1.1", "react-dom": "16.13.0", "react-icons": "^3.10.0", @@ -157,10 +158,10 @@ }, "dependencies": { "@ant-design/icons": "^4.7.0", - "@handsontable/react": "3.0.0", + "@handsontable/react": "2.1.0", "antd": "4.22.5", "classnames": "^2.2.6", - "handsontable": "7.0.1", + "handsontable": "6.2.2", "highlight.js": "^10.5.0", "lodash": "^4.17.15", "moment": "^2.22.2", diff --git a/scripts/const.sh b/scripts/const.sh index 37c4bf559..01eece088 100755 --- a/scripts/const.sh +++ b/scripts/const.sh @@ -1,13 +1,13 @@ #!/bin/bash # Project name -export project_name="dt-react-component"; +export project_name="dt-react-component-v3"; # Temporary store project export temp_path="/home/temp/$project_name"; # Server nginx root path export server_root_path="/home/app/$project_name"; -# 3.10.x testing enviroment export server="*****"; +# 3.x testing enviroment echo "project name: $project_name" echo "temp path: $temp_path" diff --git a/scripts/deploy.sh b/scripts/deploy.sh index e045c33ed..fd3eab359 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,5 +1,6 @@ #!/bin/bash -# + +# 部署文档执行 `yarn deploy`,需要先将 `const.sh` 里的 server 改为 225 的机器 ip # 1. Build project locally; # 2. Upload dist to the temp path of target server ; # 3. Login remote ssh server; diff --git a/src/components/InterruptController/index.tsx b/src/components/InterruptController/index.tsx index abc57cadc..f1bd6076c 100644 --- a/src/components/InterruptController/index.tsx +++ b/src/components/InterruptController/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -const ControllerServer =

(Component: React.ComponentType

): any => { +const ControllerServer =

(Component: any): any => { return class extends React.Component

{ controller = new AbortController(); componentWillUnmount() { diff --git a/src/components/blockHeader/__tests__/blockHeader.test.tsx b/src/components/blockHeader/__tests__/blockHeader.test.tsx index 4b4b2af73..123d0733b 100644 --- a/src/components/blockHeader/__tests__/blockHeader.test.tsx +++ b/src/components/blockHeader/__tests__/blockHeader.test.tsx @@ -121,4 +121,18 @@ describe('test BlockHeader render', () => { const titleBoxWrap1 = container1.firstChild.firstChild.firstChild; expect(titleBoxWrap1.childNodes.length).toEqual(3); }); + test('should render BlockHeader correct margin-bottom', () => { + const { container: noStyle } = render(); + expect(noStyle.querySelector('.dtc-block-header')).not.toHaveAttribute('style'); + const { container: defaultBottom } = render( + + ); + expect(defaultBottom.querySelector('.dtc-block-header')).toHaveStyle({ marginBottom: 16 }); + const { container: customizeBottom } = render( + + ); + expect(customizeBottom.querySelector('.dtc-block-header')).toHaveStyle({ + marginBottom: 10, + }); + }); }); diff --git a/src/components/blockHeader/index.tsx b/src/components/blockHeader/index.tsx index 19ae06769..ac41e5fda 100644 --- a/src/components/blockHeader/index.tsx +++ b/src/components/blockHeader/index.tsx @@ -1,10 +1,11 @@ import React, { useState } from 'react'; import { QuestionCircleOutlined, UpOutlined } from '@ant-design/icons'; import { Tooltip } from 'antd'; +import useLocale from '../locale/useLocale'; export interface BlockHeaderProps { // 标题 - title: string; + title: React.ReactNode; // 标题前的图标,默认是一个色块 beforeTitle?: React.ReactNode; // 标题后的提示图标或文案 @@ -19,6 +20,8 @@ export interface BlockHeaderProps { * 默认 false */ isSmall?: boolean; + hasBottom?: boolean; + spaceBottom?: number; // 标题一行的样式类名 titleRowClassName?: string; // 标题的样式类名 @@ -38,6 +41,8 @@ const BlockHeader: React.FC = function (props) { afterTitle = '', tooltip = '', isSmall = false, + hasBottom = false, + spaceBottom = 0, titleRowClassName = '', titleClassName = '', showBackground = true, @@ -49,10 +54,16 @@ const BlockHeader: React.FC = function (props) { const { beforeTitle =

} = props; const questionTooltip = tooltip && ( - + ); const newAfterTitle = afterTitle || questionTooltip; + let bottomStyle; + if (hasBottom) bottomStyle = { marginBottom: 16 }; + if (spaceBottom) bottomStyle = { marginBottom: spaceBottom }; + + const locale = useLocale('BlockHeader'); + const [expand, setExpand] = useState(defaultExpand); const handleExpand = (expand) => { @@ -61,7 +72,7 @@ const BlockHeader: React.FC = function (props) { onChange?.(expand); }; return ( -
+
= function (props) { {addonAfter &&
{addonAfter}
} {children && (
-
{expand ? '收起' : '展开'}
+
{expand ? locale.collapse : locale.expand}
)} diff --git a/src/components/blockHeader/style.scss b/src/components/blockHeader/style.scss index 9197ee69f..fbe94762c 100644 --- a/src/components/blockHeader/style.scss +++ b/src/components/blockHeader/style.scss @@ -40,6 +40,7 @@ $card_prefix: "dtc-block-header"; flex: 1; display: flex; align-items: center; + min-width: 0; .#{$card_prefix}-before-title { margin-right: 8px; .default { @@ -48,17 +49,25 @@ $card_prefix: "dtc-block-header"; background-color: #1D78FF; } .small { - height: 12px; + height: 16px; } } .#{$card_prefix}-title { color: #3D446E; font-weight: 500; margin-right: 4px; + flex: 1; + min-width: 0; } .#{$card_prefix}-after-title { + display: flex; + align-items: center; color: #8B8FA8; font-size: 12px; + &-icon { + font-size: 16px; + color: #B1B4C5; + } } } diff --git a/src/components/chromeDownload/index.tsx b/src/components/chromeDownload/index.tsx index af1806b86..015236e9a 100644 --- a/src/components/chromeDownload/index.tsx +++ b/src/components/chromeDownload/index.tsx @@ -1,14 +1,18 @@ import React from 'react'; -import utils from '../utils'; import classNames from 'classnames'; + +import utils from '../utils'; +import useLocale, { Locale } from '../locale/useLocale'; + const prefixCls = 'dtc-chrome'; interface ChromeDownloadProps { downloadChrome?: (chromeOfOsType?: 'macChrome' | 'windowsChrome' | 'others') => void; className?: string; style?: React.CSSProperties; + locale?: Locale['ChromeDownload']; } -export default class ChromeDownload extends React.Component { +class ChromeDownload extends React.Component { constructor(props: ChromeDownloadProps) { super(props); } @@ -28,21 +32,18 @@ export default class ChromeDownload extends React.Component -
- 本产品当前可兼容Chrome66以及以上版本,请您更换至最新的谷歌(Chrome)浏览器 -
-
- {this.renderDivide('点击即可下载,更新即刻搞定')} -
+
{locale.description}
+
{this.renderDivide(locale.download)}
) => { + const locale = useLocale('ChromeDownload'); + return ; +}; + +export default ChromeDownloadWrapper; diff --git a/src/components/chromeDownload/style.scss b/src/components/chromeDownload/style.scss index a6fc8160a..2cf1d3c3f 100644 --- a/src/components/chromeDownload/style.scss +++ b/src/components/chromeDownload/style.scss @@ -1,12 +1,11 @@ $prefix: "dtc-chrome"; .#{$prefix}-chrome-download { background: #F2F7FA; - margin-top: 50px; text-align: center; - overflow-y: auto; + overflow: auto; .#{$prefix}-pic-update { - width: 182px; - margin: 148px 0 17.5px; + width: 250px; + margin: 160px 0 8px; } .#{$prefix}-divide { margin: 80.5px 0 60px; @@ -18,7 +17,7 @@ $prefix: "dtc-chrome"; } .#{$prefix}-download { width: 160px; - margin: 0 auto; + margin: 0 auto 24px; cursor: pointer; .#{$prefix}-chrome-version { margin-top: 16.5px; diff --git a/src/components/configProvider/index.tsx b/src/components/configProvider/index.tsx new file mode 100644 index 000000000..1b6749637 --- /dev/null +++ b/src/components/configProvider/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import { LocaleContext } from '../locale/useLocale'; + +const ConfigProvider = ({ locale, children }) => { + return {children}; +}; + +export default ConfigProvider; diff --git a/src/components/cookies/index.tsx b/src/components/cookies/index.tsx index 536a7f9ab..28f7cb11a 100644 --- a/src/components/cookies/index.tsx +++ b/src/components/cookies/index.tsx @@ -18,7 +18,7 @@ export interface CookiesProps { const defaultIntervalTime = 200; class Cookies extends React.Component { _currentCookies: string; - private _timerId: NodeJS.Timer | null = null; + private _timerId: ReturnType | null = null; componentDidMount() { this.initEvent(); diff --git a/src/components/copyIcon/index.tsx b/src/components/copyIcon/index.tsx index a86a5a1ef..6fc624fb9 100644 --- a/src/components/copyIcon/index.tsx +++ b/src/components/copyIcon/index.tsx @@ -1,15 +1,17 @@ import * as React from 'react'; import { Tooltip, message } from 'antd'; import { CopyOutlined } from '@ant-design/icons'; +import useLocale, { Locale } from '../locale/useLocale'; export interface CopyIconProps { text: string; style?: React.CSSProperties; title?: string; customRender?: React.ReactNode; + locale?: Locale['CopyIcon']; } -export default class CopyIcon extends React.Component { +class CopyIcon extends React.Component { fakeHandlerCallback: () => void; fakeHandler: EventListener | void; fakeElem: HTMLTextAreaElement; @@ -82,15 +84,16 @@ export default class CopyIcon extends React.Component { } handleResult(succeeded: any) { + const { locale } = this.props; if (succeeded) { - message.success('复制成功'); + message.success(locale.copied); } else { - message.error('不支持'); + message.error(locale.notSupport); } } render() { - let { customRender, text, style, title, ...rest } = this.props; + let { customRender, text, style, title, locale, ...rest } = this.props; style = { cursor: 'pointer', @@ -101,7 +104,7 @@ export default class CopyIcon extends React.Component { return customRender ? ( {customRender} ) : ( - + { ); } } + +const CopyIconWrapper = (props: Omit) => { + const locale = useLocale('CopyIcon'); + return ; +}; + +export default CopyIconWrapper; diff --git a/src/components/editCell/index.tsx b/src/components/editCell/index.tsx index 2ff2f8687..e2b7ffd27 100644 --- a/src/components/editCell/index.tsx +++ b/src/components/editCell/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Input } from 'antd'; import EllipsisText from '../ellipsisText'; import classNames from 'classnames'; +import useLocale, { Locale } from '../locale/useLocale'; type EditType = string | number; export interface EditCellProps { @@ -9,6 +10,7 @@ export interface EditCellProps { value: string; keyField: string; isView?: boolean; + locale?: Locale['EditCell']; onHandleEdit: (keyField: string, editValue: EditType) => void; } export interface EditCellStates { @@ -16,7 +18,7 @@ export interface EditCellStates { editValue: EditType; } -export default class EditCell extends React.PureComponent { +class EditCell extends React.PureComponent { state: EditCellStates = { isEdit: false, editValue: '', @@ -47,7 +49,7 @@ export default class EditCell extends React.PureComponent {isEdit ? ( @@ -57,16 +59,23 @@ export default class EditCell extends React.PureComponent - 完成 - 取消 + {locale.complete} + {locale.cancel}
) : ( <> - {!isView && 修改} + {!isView && {locale.modify}} )}
); } } + +const EditCellWrapper = (props: Omit) => { + const locale = useLocale('EditCell'); + return ; +}; + +export default EditCellWrapper; diff --git a/src/components/editInput/__tests__/editInput.test.tsx b/src/components/editInput/__tests__/editInput.test.tsx index 65178ef9f..42eaa6cd1 100644 --- a/src/components/editInput/__tests__/editInput.test.tsx +++ b/src/components/editInput/__tests__/editInput.test.tsx @@ -33,7 +33,7 @@ describe('test edit input', () => { }); test('should render message when length more then max', () => { fireEvent.change(element, { target: { value: '12345678910' } }); - expect(wrapper.getByText('字符长度不可超过10')).toBeInTheDocument(); + expect(wrapper.getByText('字符长度不可超过${max}')).toBeInTheDocument(); expect(element.value).toEqual('1234567891'); }); diff --git a/src/components/editInput/index.tsx b/src/components/editInput/index.tsx index 4c1384103..58afb3afc 100644 --- a/src/components/editInput/index.tsx +++ b/src/components/editInput/index.tsx @@ -1,16 +1,18 @@ import React from 'react'; import { Input, message } from 'antd'; +import useLocale, { Locale } from '../locale/useLocale'; export interface EditInputProps { value?: string | number; onChange?: (e) => void; max?: number; + locale?: Locale['EditInput']; [propName: string]: any; } export interface EditInputPropsStates { value: string | number; } -export default class EditInput extends React.PureComponent { +class EditInput extends React.PureComponent { constructor(props: EditInputProps) { super(props); this.state = { @@ -34,10 +36,11 @@ export default class EditInput extends React.PureComponent) => { + const { locale } = this.props; const value = e.target.value; const { max = 64 } = this.props; if (value && max && value.length > max) { - message.warning(`字符长度不可超过${max}`); + message.warning(locale.description); this.setState({ value: value.substring(0, max), }); @@ -61,3 +64,10 @@ export default class EditInput extends React.PureComponent) => { + const locale = useLocale('EditInput'); + return ; +}; + +export default EditInputWrapper; diff --git a/src/components/ellipsisText/__tests__/ellipsisText.test.tsx b/src/components/ellipsisText/__tests__/ellipsisText.test.tsx index be77cdd71..d52dc70ca 100644 --- a/src/components/ellipsisText/__tests__/ellipsisText.test.tsx +++ b/src/components/ellipsisText/__tests__/ellipsisText.test.tsx @@ -48,6 +48,32 @@ describe('test ellipsis text if not set max width', () => { }); }); +describe('auto calculate ellipsis text if the parent element does not exist', () => { + beforeEach(() => { + Object.defineProperty(window, 'getComputedStyle', { + value: jest.fn(() => ({ + paddingLeft: '0px', + paddingRight: '0px', + })), + }); + + wrapper = render(); + }); + + afterEach(() => { + cleanup(); + }); + + test('render correct value in ellipsis', () => { + const { getByText } = wrapper; + const { value } = defaultProps; + element = getByText(value); + + expect(element).toBeInTheDocument(); + expect(element.style.maxWidth).toBe('120px'); + }); +}); + describe('test ellipsis text if set max width', () => { beforeEach(() => { Object.defineProperty(window, 'getComputedStyle', { diff --git a/src/components/ellipsisText/index.tsx b/src/components/ellipsisText/index.tsx index 550337cc1..55093bb94 100644 --- a/src/components/ellipsisText/index.tsx +++ b/src/components/ellipsisText/index.tsx @@ -24,6 +24,8 @@ export interface NewHTMLElement extends HTMLElement { currentStyle?: CSSStyleDeclaration; } +const DEFAULT_MAX_WIDTH = 120; + export default class EllipsisText extends PureComponent { ellipsisRef: HTMLElement | null = null; state = { @@ -57,7 +59,8 @@ export default class EllipsisText extends PureComponent { - if (!ele) return; + // The default maximum width is 120px when the element does not exist + if (!ele) return DEFAULT_MAX_WIDTH; const { scrollWidth, offsetWidth, parentElement } = ele; // If inline element, find the parent element if (scrollWidth === 0) { @@ -78,6 +81,8 @@ export default class EllipsisText extends PureComponent { const { maxWidth } = this.props; + // if props has maxWidth don't have to calculate the text length + if (maxWidth) return; const ellipsisNode = this.ellipsisRef; const rangeWidth = this.getRangeWidth(ellipsisNode); const ellipsisWidth = this.getMaxWidth(ellipsisNode.parentElement); diff --git a/src/components/errorBoundary/index.tsx b/src/components/errorBoundary/index.tsx index a2cd2b3a7..27fba89cb 100644 --- a/src/components/errorBoundary/index.tsx +++ b/src/components/errorBoundary/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import LoadError from '../loadError'; interface ErrorBoundaryProps { - children?: React.ReactNode; + children?: React.ReactNode | React.ReactComponentElement; } interface ErrorBoundaryStates { @@ -28,6 +28,6 @@ export default class ErrorBoundary extends React.Component< if (this.state.hasError) { return ; } - return this.props.children; + return <>{this.props.children}; } } diff --git a/src/components/fullscreen/index.tsx b/src/components/fullscreen/index.tsx index 68d52fd2a..4e6a2a34d 100644 --- a/src/components/fullscreen/index.tsx +++ b/src/components/fullscreen/index.tsx @@ -3,6 +3,7 @@ import { Button } from 'antd'; import MyIcon from './icon'; import KeyEventListener from '../keyEventListener'; +import useLocale, { Locale } from '../locale/useLocale'; const { KeyCombiner } = KeyEventListener; declare let document: any; @@ -14,12 +15,13 @@ export interface FullscreenProps { iconStyle?: object; fullIcon?: React.ReactNode; exitFullIcon?: React.ReactNode; + locale?: Locale['Fullscreen']; [propName: string]: any; } export interface FullscreenState { isFullScreen: boolean; } -export default class Fullscreen extends React.Component { +class Fullscreen extends React.Component { state: FullscreenState = { isFullScreen: false, }; @@ -136,8 +138,8 @@ export default class Fullscreen extends React.Component) => { + const locale = useLocale('Fullscreen'); + return ; +}; + +export default FullscreenWrapper; diff --git a/src/components/globalLoading/index.tsx b/src/components/globalLoading/index.tsx index 196797c5f..eb5d085a1 100644 --- a/src/components/globalLoading/index.tsx +++ b/src/components/globalLoading/index.tsx @@ -1,5 +1,6 @@ import classNames from 'classnames'; import React from 'react'; +import useLocale, { Locale } from '../locale/useLocale'; export interface GlobalLoadingProps { className?: string; @@ -8,19 +9,23 @@ export interface GlobalLoadingProps { mainBackground?: string; circleBackground?: string; titleColor?: string; + locale?: Locale['GlobalLoading']; } -export default class GlobalLoading extends React.Component { +class GlobalLoading extends React.Component { render() { const { prefix = '', - loadingTitle = '应用加载中,请等候~', + loadingTitle, mainBackground = '#F2F7FA', circleBackground = '#1D78FF', titleColor = '#3D446E', className = '', + locale, } = this.props; + const newLoadingTitle = loadingTitle || locale.loading; + return (
-
{`${prefix} ${loadingTitle}`}
+
{`${prefix} ${newLoadingTitle}`}
@@ -45,3 +53,10 @@ export default class GlobalLoading extends React.Component) => { + const locale = useLocale('GlobalLoading'); + return ; +}; + +export default GlobalLoadingWrapper; diff --git a/src/components/globalLoading/style.scss b/src/components/globalLoading/style.scss index 2dabf97c6..60c43f590 100644 --- a/src/components/globalLoading/style.scss +++ b/src/components/globalLoading/style.scss @@ -14,8 +14,8 @@ text-align: center; right: 0; margin: auto; - min-width: 300px; height: 160px; + white-space: nowrap; } .dtc-loading-title { diff --git a/src/components/goBack/goBackButton.tsx b/src/components/goBack/goBackButton.tsx index 7b4dc93e4..09017df5d 100644 --- a/src/components/goBack/goBackButton.tsx +++ b/src/components/goBack/goBackButton.tsx @@ -2,8 +2,9 @@ import * as React from 'react'; import { Button } from 'antd'; import { browserHistory, hashHistory } from 'react-router'; import { GoBackButtonProps } from './index'; +import useLocale from '../locale/useLocale'; -export default class GoBackButton extends React.Component { +class GoBackButton extends React.Component { go = () => { const { url, history, autoClose } = this.props; @@ -25,11 +26,18 @@ export default class GoBackButton extends React.Component - {title || '返回'} + {title || locale.back} ); } } + +const GoBackButtonWrapper = (props: Omit) => { + const locale = useLocale('GoBack'); + return ; +}; + +export default GoBackButtonWrapper; diff --git a/src/components/goBack/index.tsx b/src/components/goBack/index.tsx index 3faf3f58c..add1228dc 100644 --- a/src/components/goBack/index.tsx +++ b/src/components/goBack/index.tsx @@ -1,3 +1,4 @@ +import { Locale } from '../locale/useLocale'; import GoBack from './goBack'; import GoBackButton from './goBackButton'; @@ -9,6 +10,7 @@ export interface GoBackProps { } export interface GoBackButtonProps extends GoBackProps { title?: string; + locale?: Locale['GoBack']; } GoBack.GoBackButton = GoBackButton; diff --git a/src/components/index.tsx b/src/components/index.tsx index 6c2d6d68b..4c53105a1 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -34,3 +34,6 @@ export { default as TextMark } from './textMark'; export { default as ToolModal } from './toolModal'; export { default as ProgressLine } from './progressLine'; export { default as Empty } from './empty'; +export { default as ConfigProvider } from './configProvider'; +export { default as zhCN } from './locale/zh-CN'; +export { default as enUS } from './locale/en-US'; diff --git a/src/components/loadError/index.tsx b/src/components/loadError/index.tsx index 4768004c6..fd43bf13f 100644 --- a/src/components/loadError/index.tsx +++ b/src/components/loadError/index.tsx @@ -1,22 +1,23 @@ import React from 'react'; +import useLocale from '../locale/useLocale'; const LoadError: React.FC = function () { + const locale = useLocale('LoadError'); return (
- 

- 发现新版本,请 + {locale.please} { location.reload(); }} > - 刷新 + {locale.refresh} - 获取新版本。 + {locale.get}

-

若该提示长时间存在,请联系管理员。

+

{locale.title}

); diff --git a/src/components/locale/en-US.ts b/src/components/locale/en-US.ts new file mode 100644 index 000000000..fc7b74352 --- /dev/null +++ b/src/components/locale/en-US.ts @@ -0,0 +1,82 @@ +import { Locale } from './useLocale'; + +const localeValues: Locale = { + locale: 'en-US', + BlockHeader: { + expand: 'Expand', + collapse: 'Collapse', + }, + ChromeDownload: { + description: + 'This product is currently compatible with Chrome 66 and above. Please switch to the latest Google (Chrome) browser.', + download: 'Click to download, update instantly.', + }, + CopyIcon: { + copied: 'Copied', + notSupport: 'Not Support', + copy: 'Copy', + }, + EditCell: { + complete: 'Complete', + cancel: 'Cancel', + modify: 'Modify', + }, + EditInput: { + description: 'The character length cannot exceed ${max}', + }, + Fullscreen: { + exitFull: 'Exit Full Screen', + full: 'Full Screen', + }, + GlobalLoading: { + loading: 'The application is loading, please wait~', + }, + GoBack: { + back: 'GoBack', + }, + LoadError: { + please: 'A new version has been found. Please', + get: 'to get the new version.', + refresh: ' refresh ', + title: 'If this prompt persists for a long time, please contact the administrator.', + }, + ModalWithForm: { + okText: 'Ok', + cancelText: 'Cancel', + }, + MulSelectDropdown: { + open: 'Open', + cancelText: 'Cancel', + okText: 'Ok', + selectAll: 'Select All', + }, + MultiSearchInput: { + case: 'Case-sensitive match', + precise: 'Exact match', + front: 'Head match', + tail: 'Tail match', + }, + MxGraph: { + newNode: 'New node', + }, + NotFound: { + description: 'Dear, did you go to the wrong place?', + }, + ProgressLine: { + description: 'No description yet', + }, + RenderFormItem: { + description: '${label} is empty', + }, + SearchModal: { + title: 'Search and open', + placeholder: 'Please enter', + }, + SpreadSheet: { + description: 'No Data', + copy: 'Copy', + copyAll: 'Copy values ​​and column names', + }, +}; + +export default localeValues; diff --git a/src/components/locale/useLocale.tsx b/src/components/locale/useLocale.tsx new file mode 100644 index 000000000..5ceb4159a --- /dev/null +++ b/src/components/locale/useLocale.tsx @@ -0,0 +1,85 @@ +import { createContext, useContext, useMemo } from 'react'; + +import defaultLocaleData from './zh-CN'; + +export interface Locale { + locale: string; + BlockHeader?: { expand: string; collapse: string }; + ChromeDownload?: { description: string; download: string }; + CopyIcon?: { copied: string; notSupport: string; copy: string }; + EditCell?: { complete: string; cancel: string; modify: string }; + EditInput?: { description: string }; + Fullscreen?: { exitFull: string; full: string }; + GlobalLoading?: { + loading: string; + }; + GoBack?: { + back: string; + }; + LoadError?: { + please: string; + get: string; + refresh: string; + title: string; + }; + ModalWithForm?: { + okText: string; + cancelText: string; + }; + MulSelectDropdown?: { + open: string; + cancelText: string; + okText: string; + selectAll: string; + }; + MultiSearchInput?: { + case: string; + precise: string; + front: string; + tail: string; + }; + MxGraph?: { newNode: string }; + NotFound?: { + description: string; + }; + ProgressLine?: { + description: string; + }; + RenderFormItem?: { + description: string; + }; + SearchModal?: { + title: string; + placeholder: string; + }; + SpreadSheet?: { + description: string; + copy: string; + copyAll: string; + }; +} + +export interface LocaleContextProps { + locale: Locale; +} + +export const LocaleContext = createContext(undefined); + +export type LocaleComponentName = keyof Locale; + +const useLocale = ( + componentName: C +): NonNullable => { + const fullLocale = useContext(LocaleContext); + + const getLocale = useMemo(() => { + const locale = defaultLocaleData[componentName] ?? {}; + const localeFromContext = fullLocale?.locale[componentName] ?? {}; + + return Object.assign({}, locale, localeFromContext) as NonNullable; + }, [componentName, fullLocale]); + + return getLocale; +}; + +export default useLocale; diff --git a/src/components/locale/zh-CN.ts b/src/components/locale/zh-CN.ts new file mode 100644 index 000000000..5967d76ec --- /dev/null +++ b/src/components/locale/zh-CN.ts @@ -0,0 +1,81 @@ +import { Locale } from './useLocale'; + +const localeValues: Locale = { + locale: 'zh-CN', + BlockHeader: { + expand: '展开', + collapse: '收起', + }, + ChromeDownload: { + description: '本产品当前可兼容Chrome66以及以上版本,请您更换至最新的谷歌(Chrome)浏览器', + download: '点击即可下载,更新即刻搞定', + }, + CopyIcon: { + copied: '复制成功', + notSupport: '不支持', + copy: '复制', + }, + EditCell: { + complete: '完成', + cancel: '取消', + modify: '修改', + }, + EditInput: { + description: '字符长度不可超过${max}', + }, + Fullscreen: { + exitFull: '退出全屏', + full: '全屏', + }, + GlobalLoading: { + loading: '应用加载中,请等候~', + }, + GoBack: { + back: '返回', + }, + LoadError: { + please: '发现新版本,请', + get: '获取新版本。', + refresh: '刷新', + title: '若该提示长时间存在,请联系管理员。', + }, + ModalWithForm: { + okText: '确定', + cancelText: '取消', + }, + MulSelectDropdown: { + open: '打开', + cancelText: '取消', + okText: '确定', + selectAll: '全选', + }, + MultiSearchInput: { + case: '区分大小写匹配', + precise: '精确匹配', + front: '头部匹配', + tail: '尾部匹配', + }, + MxGraph: { + newNode: '新节点', + }, + NotFound: { + description: '亲,是不是走错地方了?', + }, + ProgressLine: { + description: '暂无描述', + }, + RenderFormItem: { + description: '${label}为空', + }, + SearchModal: { + title: '搜索并打开', + placeholder: '请输入', + }, + SpreadSheet: { + description: '暂无数据', + copy: '复制', + copyAll: '复制值以及列名', + }, +}; + +export default localeValues; diff --git a/src/components/markdownRender/index.tsx b/src/components/markdownRender/index.tsx index 275d76ba9..3f1b0434e 100644 --- a/src/components/markdownRender/index.tsx +++ b/src/components/markdownRender/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import showdown from 'showdown'; -import hljs from 'highlight.js'; +import hljs from 'highlight.js/lib/core'; import sql from 'highlight.js/lib/languages/sql'; import classNames from 'classnames'; diff --git a/src/components/modalWithForm/__tests__/modalWithForm.test.tsx b/src/components/modalWithForm/__tests__/modalWithForm.test.tsx index 0ecf4064f..e40ea0812 100644 --- a/src/components/modalWithForm/__tests__/modalWithForm.test.tsx +++ b/src/components/modalWithForm/__tests__/modalWithForm.test.tsx @@ -73,18 +73,6 @@ test('should toggle modalWithForm when click button', () => { expect(element).toBeValid(); }); -test('should change input value when input', () => { - // 点击按钮打开模态框 - fireEvent.click(wrapper.getByText('click')); - const ele = wrapper.getByTestId('test-input'); - ele.onchange = jest.fn(); - fireEvent.change(ele, { target: { value: '1' } }); - expect(ele.onchange).toHaveBeenCalled(); - expect(ele.value).toBe('1'); - const eleQuit = wrapper.getByText('quit'); - fireEvent.click(eleQuit); -}); - test('should trigger submit methond when form validate successful', () => { fireEvent.click(wrapper.getByText('click')); const eleInput = wrapper.getByTestId('test-input'); @@ -97,18 +85,6 @@ test('should trigger submit methond when form validate successful', () => { expect(eleOk.onclick).toHaveBeenCalled(); }); -test('should render ModalWithForm render correct button props', () => { - fireEvent.click(wrapper.getByText('click')); - const eleOk = wrapper.getByText('ok'); - expect(eleOk.parentNode).toHaveClass('ant-btn-dangerous'); -}); - -test('should render ModalWithForm render correct width props', async () => { - fireEvent.click(wrapper.getByText('click')); - const eleModal = document.querySelector('.ant-modal'); - expect(eleModal).toHaveStyle({ width: '400px' }); -}); - test('test useFilterFormProps', () => { const { result } = renderHook(() => useFilterFormProps({ diff --git a/src/components/modalWithForm/index.tsx b/src/components/modalWithForm/index.tsx index 3e764b734..95bc98081 100644 --- a/src/components/modalWithForm/index.tsx +++ b/src/components/modalWithForm/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Modal, Form, FormProps } from 'antd'; +import { Form, FormProps, Modal } from 'antd'; import { ButtonProps, ButtonType } from 'antd/es/button'; +import useLocale from '../locale/useLocale'; export interface IProps { confirmLoading?: boolean; @@ -9,7 +10,7 @@ export interface IProps { okType?: ButtonType; record?: string | number | object; visible?: boolean; - title?: React.ReactNode | string; + title?: React.ReactNode; width?: string | number; modelClass?: string; footer?: React.ReactNode; @@ -23,9 +24,10 @@ export interface IProps { onCancel?: (func: Function) => any; onSubmit?: (values: any, record: any) => void; [key: string]: any; + maskClosable?: boolean; } -type ModalProps = IProps & FormProps; +type ModalProps = IProps & Omit; export const FORM_PROPS = [ 'colon', @@ -62,12 +64,14 @@ export const useFilterFormProps = (props = {}) => { }; const ModalForm = (props: ModalProps) => { + const locale = useLocale('ModalWithForm'); + const { title, visible, record, - okText = '确定', - cancelText = '取消', + okText = locale.okText, + cancelText = locale.cancelText, modelClass, okType, width, @@ -80,6 +84,8 @@ const ModalForm = (props: ModalProps) => { onSubmit, children, okButtonProps, + maskClosable = false, + afterClose, } = props; const formProps = useFilterFormProps(); @@ -98,6 +104,11 @@ const ModalForm = (props: ModalProps) => { form.resetFields(); }; + const handleAfterClose = () => { + afterClose?.(); + form.resetFields(); + }; + return ( { cancelButtonProps={cancelButtonProps} confirmLoading={confirmLoading} okButtonProps={okButtonProps} + maskClosable={maskClosable} + afterClose={handleAfterClose} >
{React.cloneElement(children, { form, ...props })} diff --git a/src/components/mulSelectDropdown/__tests__/mulSelectDropdown.test.tsx b/src/components/mulSelectDropdown/__tests__/mulSelectDropdown.test.tsx index e09745cfc..4ab2fb807 100644 --- a/src/components/mulSelectDropdown/__tests__/mulSelectDropdown.test.tsx +++ b/src/components/mulSelectDropdown/__tests__/mulSelectDropdown.test.tsx @@ -2,6 +2,9 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import MulSelectDropdown from '../index'; +const cancelText = '取消'; +const okText = '确定'; + describe('mulSelectDropdown Component test', () => { test('should render correct', () => { const expectValues = { @@ -10,6 +13,8 @@ describe('mulSelectDropdown Component test', () => { { label: '选项二', value: 2, disabled: true }, ], value: [2], + cancelText, + okText, onOk: (value) => { console.log(value); }, @@ -20,13 +25,7 @@ describe('mulSelectDropdown Component test', () => { ), }; const { getByTestId } = render( - + ); fireEvent.click(getByTestId('drop_down_btn')); @@ -40,7 +39,12 @@ describe('mulSelectDropdown Component test', () => { expect(checkoutItem.classList.contains('ant-checkbox-wrapper-disabled')).toEqual(true); expect(checkoutItem.classList.contains('ant-checkbox-wrapper-checked')).toEqual(true); - fireEvent.click(getByTestId('select_cancel_btn')); + const okButton = getByTestId('select_ok_btn'); + expect(okButton.textContent.replace(' ', '')).toEqual(okText); + + const cancelButton = getByTestId('select_cancel_btn'); + expect(cancelButton.textContent.replace(' ', '')).toEqual(cancelText); + fireEvent.click(cancelButton); expect(dropdownEle.classList.contains('ant-dropdown-hidden')).toEqual(true); }); }); diff --git a/src/components/mulSelectDropdown/index.tsx b/src/components/mulSelectDropdown/index.tsx index 77a3550eb..275e90b0b 100644 --- a/src/components/mulSelectDropdown/index.tsx +++ b/src/components/mulSelectDropdown/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Checkbox, Dropdown, Button, Divider } from 'antd'; import { isEqual } from 'lodash'; import classNames from 'classnames'; +import useLocale, { Locale } from '../locale/useLocale'; interface Opts { label?: string; @@ -16,6 +17,9 @@ interface MulSelectDropdownProps { value: any[]; onOk: (sel) => void; renderNode: Function; + cancelText?: string; + okText?: string; + locale?: Locale['MulSelectDropdown']; } interface MulSelectDropdownStates { @@ -26,7 +30,7 @@ interface MulSelectDropdownStates { indeterminate: boolean; } -export default class MulSelectDropdown extends React.Component< +class MulSelectDropdown extends React.Component< MulSelectDropdownProps, MulSelectDropdownStates > { @@ -106,9 +110,15 @@ export default class MulSelectDropdown extends React.Component< popupContainer = () => document.body, options = [], className = '', - renderNode = (openFun) => 打开, + locale, + renderNode:propRenderNode, + cancelText, + okText, } = this.props; const { visible, selectVal, indeterminate, allKeys } = this.state; + const defaultRenderNode = (openFun) => {locale.open}; + const renderNode = propRenderNode || defaultRenderNode; + const overlay = (
@@ -129,18 +139,24 @@ export default class MulSelectDropdown extends React.Component< checked={selectVal.length === allKeys.length} indeterminate={indeterminate} > - 全选 + {locale.selectAll} - - 关闭 - - +
@@ -162,3 +178,11 @@ export default class MulSelectDropdown extends React.Component< ); } } + + +const MulSelectDropdownWrapper = (props: Omit) => { + const locale = useLocale("MulSelectDropdown"); + return ; +}; + +export default MulSelectDropdownWrapper; diff --git a/src/components/multiSearchInput/index.tsx b/src/components/multiSearchInput/index.tsx index df16a6b84..22dfd263b 100644 --- a/src/components/multiSearchInput/index.tsx +++ b/src/components/multiSearchInput/index.tsx @@ -1,29 +1,7 @@ import _ from 'lodash'; import { Input, Tooltip } from 'antd'; import React from 'react'; - -const searchTypeList: any = [ - { - key: 'caseSensitive', - imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAABhElEQVRYhe2VPUvDQByHf5cmrRolQyHtYJ18gy4O4qSDg64i2II4SAvFNoWgX8ShQ64RBxFd6hdwc1QXQRCEirgo7WAXhxJJ079LC+LiRQWH3jPey8PD3cEBEolEMugw0YWc8zqAqRDuh1KpNB0+adAQvoI+nPM9APuMsblisXj72wD1B3vyRHQOIAdg90ucGQTBsGmaz9lsNhCRhToBzvkCgFNVVVc7nc617/sp27bfe3MHAJaJqMkYM3zfX7Rt++07pxImAEAewHGhUHgCcK9p2hoA1Gq1KBE9xuPxtGVZS4yxV03TVkSEwgGu644A2AQwX61WXQB6LwiZTMYHYLRarUvHca6IKA1gTMQr/AaIaANAnYhOiAiMsQsiOnRdd8JxnHFFUbYURZlsNBpBIpG4EfWGCcgTkWtZ1ll/jHO+3u12twEcARgNgoAnk8kUAJWI/jZAVdWcYRgvn8c8z9uJRqND5XK5WalUZmOx2Ey73b6LRCKaruueqPtfkX+BRCKRfAAM043+Rp32BgAAAABJRU5ErkJggg==', - tip: '区分大小写匹配', - }, - { - key: 'precise', - imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAwFBMVEUAAAD///+AgICioqKSkpKcnJyUlJSbm5uVlZWXl5eWlpaWlpaYmJiZmZmWlpaVlZWVlZWWlpaVlZWYmJiWlpaYmJiWlpaXl5eYmJiXl5eXl5eWlpaYmJiYmJiXl5eYmJiYmJiWlpaXl5eXl5eWlpaWlpaXl5eWlpaWlpaYmJiXl5eXl5eYmJiYmJiXl5eYmJiXl5eWlpaXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eIXQHmAAAAP3RSTlMAAQILDhITFxggIi4vMjM1Oj9BQ0RISVFUXWBmam9zdHmBhIWGjZaXoaOkp6qvvL7EyMzR2t3g4eTn6erz+PmloSGXAAAAAWJLR0QB/wIt3gAAAJlJREFUOMtjYBgF1AUqdvYowE4ZTYEdK4QW1oPQbLZoCuyhNJ82mgCKAh1TRgwdyHw2M31BIMUtxo5DgayqpAYDg5yBsjknFgX2JgzGPMxWLAxcAuL6kpb2WEzgtzEyspZmUNOVMZDCaoW6PAODiCGDqSi/BXYFChwMDExKzEJaihJ8OLwJBLyaOLxpx0YgJJXR40JpNH2SBgAKqha54oD4rgAAAABJRU5ErkJggg==', - tip: '精确匹配', - }, - { - key: 'front', - imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAB20lEQVRYhe2QPYgTURSFz33zJtkogrI6hcUqIm5pobiVVlsq6SwEmyQwZMCfThYRXiXYSZjMzdOwYVER0gsWay2ynYiFICgoGIw2oilm8q7NBpYVMkEN28xX3nM553CAgoKCgoIpMPPLOI4X55mhcvSjvu/v38sCc2emAsYY1ev1Fnbfmfk1M2/NtYCIlIMgeDYaja7tCj8HoCQii51O5/ROrd/ve0mSnLDWHv4fBZ4qpcae5/WSJDlkjNHbUo2INgA8EpHa5D+O42PD4fAtgA3n3CtmNv9UAMAZEbngnHtHRO+DILhnrd0H4DIRPVFKPQZwpdVqlQFAa30EwK0ois5rrVcB3JxmrqeJACAiz5VSZSK6GIbhLwBg5qsAlIjc3n5b8H2/CqCfZdlXz/PuMvNalmUZgAPT/HMXIKImgA8isrbjXCeiB865TefcJoB1IqoDgFLqDoCtZrO5QkQ38vxzF1BKuTAMa8YYBQDtdvukiJwtlUqX6vX6DwDodrsv0jT9ZK1dGo/Hb0TkOjMfFJHjANxU/7wCE4wxE6MvRLQ8CQeARqPx3Tm3XKlUvkVRdN/zvKpz7uFgMKhqrU/NmvEHzPzRWrv01wYzkLfA5zRNf86zQEFBQcGe8xvNVbTHyF7uqwAAAABJRU5ErkJggg==', - tip: '头部匹配', - }, - { - key: 'tail', - imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAB9klEQVRYhe2UP4gTQRjF37fJJqcRDw0kEUTwDygIIgh2NoIoWFwjKU5QDIRjJhxoddptY32wxcyuWEi4QnK1eJ1a2HqNIAh3V6jkApcyISCzz0YhitmcSqz2B9PM+2bem2+GATIyMjIyZkwURctRFC1P0vOzDkCynKZ7sw4wjakBrLUPrLU0xlz4k43b7XZpP3X7uYIGyQ0RaQC4/0u4inPuQKVS+Vyv192P+TiOjw0Gg01jzM1pm6d2wFp7GcCc7/sawGIYhsUx7QmAt57nrfX7/c0wDA8DgDHmiHNuRHJFRDYAXPzrAAAaANrNZnMHwAff9xcAoNPpFEhulcvl81rrKyKy5/v+NWPMoohsfR+rAI4CWEgzkElCHMcHkyTpAngtIrskLwHYU0rdICnW2scicp3kVxE5CWBFKfVsrENLAB6RfCMiO0qp4Hc+E98AyVsAPpJcIwkReUXyaRzHJ4wxxz3Pu+153plut+uq1eq78bXGmFMAHpK8KiJ30jow8QpINkjGWut1rfW6Uuq5iLxIkuQugE8ADjnnbK1WeykiPx1Ea73d6/VOa62308xTO5DP5+/Nz89/GZ8bjUZLhUJhrtVq7YZheK5YLJ4dDofvc7mcXyqVRuO1QRAk08z/C9bawFobTNJn/hWLSH/WHhkZGRn/xDfA/cJ9mTtA3QAAAABJRU5ErkJggg==', - tip: '尾部匹配', - }, -]; +import useLocale, { Locale } from '../locale/useLocale'; export type SearchType = 'fuzzy' | 'precise' | 'front' | 'tail'; @@ -37,6 +15,7 @@ export interface MultiSearchInputProps { searchType?: SearchType; // input框中选中的筛选方式 filterOptions?: SearchType[]; // 数组 className?: string; + locale?: Locale['MultiSearchInput']; [propName: string]: any; } @@ -74,9 +53,36 @@ class MultiSearchInput extends React.Component< render() { const { placeholder, style, value, onChange, onSearch, onTypeChange, filterOptions } = this.state; - const { className = '', value: propsValue, searchType: propsSearchType } = this.props; + const { + className = '', + value: propsValue, + searchType: propsSearchType, + locale, + } = this.props; let searchType = this.state.searchType; searchType = propsSearchType != null ? propsSearchType : searchType; + const searchTypeList: any = [ + { + key: 'caseSensitive', + imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAABhElEQVRYhe2VPUvDQByHf5cmrRolQyHtYJ18gy4O4qSDg64i2II4SAvFNoWgX8ShQ64RBxFd6hdwc1QXQRCEirgo7WAXhxJJ079LC+LiRQWH3jPey8PD3cEBEolEMugw0YWc8zqAqRDuh1KpNB0+adAQvoI+nPM9APuMsblisXj72wD1B3vyRHQOIAdg90ucGQTBsGmaz9lsNhCRhToBzvkCgFNVVVc7nc617/sp27bfe3MHAJaJqMkYM3zfX7Rt++07pxImAEAewHGhUHgCcK9p2hoA1Gq1KBE9xuPxtGVZS4yxV03TVkSEwgGu644A2AQwX61WXQB6LwiZTMYHYLRarUvHca6IKA1gTMQr/AaIaANAnYhOiAiMsQsiOnRdd8JxnHFFUbYURZlsNBpBIpG4EfWGCcgTkWtZ1ll/jHO+3u12twEcARgNgoAnk8kUAJWI/jZAVdWcYRgvn8c8z9uJRqND5XK5WalUZmOx2Ey73b6LRCKaruueqPtfkX+BRCKRfAAM043+Rp32BgAAAABJRU5ErkJggg==', + tip: locale.case, + }, + { + key: 'precise', + imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAwFBMVEUAAAD///+AgICioqKSkpKcnJyUlJSbm5uVlZWXl5eWlpaWlpaYmJiZmZmWlpaVlZWVlZWWlpaVlZWYmJiWlpaYmJiWlpaXl5eYmJiXl5eXl5eWlpaYmJiYmJiXl5eYmJiYmJiWlpaXl5eXl5eWlpaWlpaXl5eWlpaWlpaYmJiXl5eXl5eYmJiYmJiXl5eYmJiXl5eWlpaXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eIXQHmAAAAP3RSTlMAAQILDhITFxggIi4vMjM1Oj9BQ0RISVFUXWBmam9zdHmBhIWGjZaXoaOkp6qvvL7EyMzR2t3g4eTn6erz+PmloSGXAAAAAWJLR0QB/wIt3gAAAJlJREFUOMtjYBgF1AUqdvYowE4ZTYEdK4QW1oPQbLZoCuyhNJ82mgCKAh1TRgwdyHw2M31BIMUtxo5DgayqpAYDg5yBsjknFgX2JgzGPMxWLAxcAuL6kpb2WEzgtzEyspZmUNOVMZDCaoW6PAODiCGDqSi/BXYFChwMDExKzEJaihJ8OLwJBLyaOLxpx0YgJJXR40JpNH2SBgAKqha54oD4rgAAAABJRU5ErkJggg==', + tip: locale.precise, + }, + { + key: 'front', + imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAB20lEQVRYhe2QPYgTURSFz33zJtkogrI6hcUqIm5pobiVVlsq6SwEmyQwZMCfThYRXiXYSZjMzdOwYVER0gsWay2ynYiFICgoGIw2oilm8q7NBpYVMkEN28xX3nM553CAgoKCgoIpMPPLOI4X55mhcvSjvu/v38sCc2emAsYY1ev1Fnbfmfk1M2/NtYCIlIMgeDYaja7tCj8HoCQii51O5/ROrd/ve0mSnLDWHv4fBZ4qpcae5/WSJDlkjNHbUo2INgA8EpHa5D+O42PD4fAtgA3n3CtmNv9UAMAZEbngnHtHRO+DILhnrd0H4DIRPVFKPQZwpdVqlQFAa30EwK0ois5rrVcB3JxmrqeJACAiz5VSZSK6GIbhLwBg5qsAlIjc3n5b8H2/CqCfZdlXz/PuMvNalmUZgAPT/HMXIKImgA8isrbjXCeiB865TefcJoB1IqoDgFLqDoCtZrO5QkQ38vxzF1BKuTAMa8YYBQDtdvukiJwtlUqX6vX6DwDodrsv0jT9ZK1dGo/Hb0TkOjMfFJHjANxU/7wCE4wxE6MvRLQ8CQeARqPx3Tm3XKlUvkVRdN/zvKpz7uFgMKhqrU/NmvEHzPzRWrv01wYzkLfA5zRNf86zQEFBQcGe8xvNVbTHyF7uqwAAAABJRU5ErkJggg==', + tip: locale.front, + }, + { + key: 'tail', + imgSrc: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAB9klEQVRYhe2UP4gTQRjF37fJJqcRDw0kEUTwDygIIgh2NoIoWFwjKU5QDIRjJhxoddptY32wxcyuWEi4QnK1eJ1a2HqNIAh3V6jkApcyISCzz0YhitmcSqz2B9PM+2bem2+GATIyMjIyZkwURctRFC1P0vOzDkCynKZ7sw4wjakBrLUPrLU0xlz4k43b7XZpP3X7uYIGyQ0RaQC4/0u4inPuQKVS+Vyv192P+TiOjw0Gg01jzM1pm6d2wFp7GcCc7/sawGIYhsUx7QmAt57nrfX7/c0wDA8DgDHmiHNuRHJFRDYAXPzrAAAaANrNZnMHwAff9xcAoNPpFEhulcvl81rrKyKy5/v+NWPMoohsfR+rAI4CWEgzkElCHMcHkyTpAngtIrskLwHYU0rdICnW2scicp3kVxE5CWBFKfVsrENLAB6RfCMiO0qp4Hc+E98AyVsAPpJcIwkReUXyaRzHJ4wxxz3Pu+153plut+uq1eq78bXGmFMAHpK8KiJ30jow8QpINkjGWut1rfW6Uuq5iLxIkuQugE8ADjnnbK1WeykiPx1Ea73d6/VOa62308xTO5DP5+/Nz89/GZ8bjUZLhUJhrtVq7YZheK5YLJ4dDofvc7mcXyqVRuO1QRAk08z/C9bawFobTNJn/hWLSH/WHhkZGRn/xDfA/cJ9mTtA3QAAAABJRU5ErkJggg==', + tip: locale.tail, + }, + ]; const filterList = _.filter(searchTypeList, (item: any) => { return _.includes(filterOptions, item.key); }); @@ -157,4 +163,9 @@ class MultiSearchInput extends React.Component< } } -export default MultiSearchInput; +const MultiSearchInputWrapper = (props) => { + const locale = useLocale('MultiSearchInput'); + return ; +}; + +export default MultiSearchInputWrapper; diff --git a/src/components/mxGraph/factory.tsx b/src/components/mxGraph/factory.tsx index b0a5d6b91..50ca39ab5 100644 --- a/src/components/mxGraph/factory.tsx +++ b/src/components/mxGraph/factory.tsx @@ -113,16 +113,11 @@ class MxFactory { this.node.setAttribute( 'stroke', // Prevent transform css constiables into lower case - strokeColor.startsWith('const') - ? strokeColor - : strokeColor.toLowerCase() + strokeColor.startsWith('const') ? strokeColor : strokeColor.toLowerCase() ); if (s.alpha < 1 || s.strokeAlpha < 1) { - this.node.setAttribute( - 'stroke-opacity', - s.alpha * s.strokeAlpha - ); + this.node.setAttribute('stroke-opacity', s.alpha * s.strokeAlpha); } const sw = this.getCurrentStrokeWidth(); @@ -138,9 +133,7 @@ class MxFactory { if (s.dashed) { this.node.setAttribute( 'stroke-dasharray', - this.createDashPattern( - (s.fixDash ? 1 : s.strokeWidth) * s.scale - ) + this.createDashPattern((s.fixDash ? 1 : s.strokeWidth) * s.scale) ); } }; @@ -175,10 +168,7 @@ class MxFactory { this.root.ownerDocument === document ) { // Workaround for potential base tag and brackets must be escaped - const base = this.getBaseUrl().replace( - /([()])/g, - '\\$1' - ); + const base = this.getBaseUrl().replace(/([()])/g, '\\$1'); this.node.setAttribute('fill', `url(${base}#${id})`); } else { this.node.setAttribute('fill', `url(#${id})`); @@ -188,9 +178,7 @@ class MxFactory { this.node.setAttribute( 'fill', // Prevent transform css constiables into lower case - fillColor.startsWith('const') - ? fillColor - : fillColor.toLowerCase() + fillColor.startsWith('const') ? fillColor : fillColor.toLowerCase() ); } } @@ -252,12 +240,7 @@ class MxFactory { ...(userEdgeStyle || {}), }); - mxGraphView.prototype.updateFloatingTerminalPoint = function ( - edge, - start, - end, - source - ) { + mxGraphView.prototype.updateFloatingTerminalPoint = function (edge, start, end, source) { if (config?.getPortOffset) { const next = this.getNextPoint(edge, end, source); if (!start.text) return; @@ -287,7 +270,10 @@ class MxFactory { edge.setAbsoluteTerminalPoint(new MxPoint(x, y), source); } else { - edge.setAbsoluteTerminalPoint(this.getFloatingTerminalPoint(edge, start, end, source), source); + edge.setAbsoluteTerminalPoint( + this.getFloatingTerminalPoint(edge, start, end, source), + source + ); } }; @@ -361,11 +347,7 @@ class MxFactory { * 初始化 graph 相关配置 */ public initContainerScroll = () => { - const { - mxRectangle: MxRectangle, - mxPoint: MxPoint, - mxUtils, - } = this.mxInstance; + const { mxRectangle: MxRectangle, mxPoint: MxPoint, mxUtils } = this.mxInstance; if (this.mxGraph) { const graph = this.mxGraph; /** @@ -393,11 +375,11 @@ class MxFactory { graph.getPageSize = function (this: mxGraph & { scrollTileSize: mxRectangle }) { return this.pageVisible ? new MxRectangle( - 0, - 0, - this.pageFormat.width * this.pageScale, - this.pageFormat.height * this.pageScale - ) + 0, + 0, + this.pageFormat.width * this.pageScale, + this.pageFormat.height * this.pageScale + ) : this.scrollTileSize!; }; @@ -408,9 +390,7 @@ class MxFactory { * page count. */ graph.getPageLayout = function () { - const size = this.pageVisible - ? this.getPageSize!() - : this.scrollTileSize!; + const size = this.pageVisible ? this.getPageSize!() : this.scrollTileSize!; const bounds = this.getGraphBounds(); if (bounds.width === 0 || bounds.height === 0) { @@ -418,12 +398,8 @@ class MxFactory { } // Computes untransformed graph bounds - const x = Math.ceil( - bounds.x / this.view.scale - this.view.translate.x - ); - const y = Math.ceil( - bounds.y / this.view.scale - this.view.translate.y - ); + const x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x); + const y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y); const w = Math.floor(bounds.width / this.view.scale); const h = Math.floor(bounds.height / this.view.scale); @@ -452,12 +428,7 @@ class MxFactory { const pages = this.getPageLayout!(); const size = this.getPageSize!(); - return new MxRectangle( - 0, - 0, - pages.width * size.width, - pages.height * size.height - ); + return new MxRectangle(0, 0, pages.width * size.width, pages.height * size.height); }; /** @@ -474,19 +445,14 @@ class MxFactory { x0: number; y0: number; }) { - if ( - this.graph.container != null && - mxUtils.hasScrollbars(this.graph.container) - ) { + if (this.graph.container != null && mxUtils.hasScrollbars(this.graph.container)) { const pad = this.graph.getPagePadding!(); const size = this.graph.getPageSize!(); // Updating scrollbars here causes flickering in quirks and is not needed // if zoom method is always used to set the current scale on the graph. - this.translate.x = - pad.x / this.scale - (this.x0 || 0) * size.width; - this.translate.y = - pad.y / this.scale - (this.y0 || 0) * size.height; + this.translate.x = pad.x / this.scale - (this.x0 || 0) * size.width; + this.translate.y = pad.y / this.scale - (this.y0 || 0) * size.height; } graphViewValidate.apply(this, arguments as any); @@ -500,10 +466,7 @@ class MxFactory { view: mxGraphView & { x0: number; y0: number }; } ) { - if ( - this.container != null && - mxUtils.hasScrollbars(this.container) - ) { + if (this.container != null && mxUtils.hasScrollbars(this.container)) { const pages = this.getPageLayout!(); const pad = this.getPagePadding!(); const size = this.getPageSize!(); @@ -513,25 +476,15 @@ class MxFactory { (2 * pad.x) / this.view.scale + pages.width * size.width ); const minh = Math.ceil( - (2 * pad.y) / this.view.scale + - pages.height * size.height + (2 * pad.y) / this.view.scale + pages.height * size.height ); const min = graph.minimumGraphSize; // LATER: Fix flicker of scrollbar size in IE quirks mode // after delayed call in window.resize event handler - if ( - min === null || - min.width !== minw || - min.height !== minh - ) { - graph.minimumGraphSize = new MxRectangle( - 0, - 0, - minw, - minh - ); + if (min === null || min.width !== minw || min.height !== minh) { + graph.minimumGraphSize = new MxRectangle(0, 0, minw, minh); } // Updates auto-translate to include padding and graph size @@ -540,8 +493,7 @@ class MxFactory { if ( !this.autoTranslate && - (this.view.translate.x !== dx || - this.view.translate.y !== dy) + (this.view.translate.x !== dx || this.view.translate.y !== dy) ) { this.autoTranslate = true; this.view.x0 = pages.x; @@ -554,10 +506,8 @@ class MxFactory { const ty = graph.view.translate.y; graph.view.setTranslate(dx, dy); - graph.container.scrollLeft += - (dx - tx) * graph.view.scale; - graph.container.scrollTop += - (dy - ty) * graph.view.scale; + graph.container.scrollLeft += (dx - tx) * graph.view.scale; + graph.container.scrollTop += (dy - ty) * graph.view.scale; this.autoTranslate = false; } @@ -590,22 +540,11 @@ class MxFactory { graph.container.scrollTop = Math.floor( Math.max( 0, - bounds.y - - Math.max( - 20, - (graph.container.clientHeight - boundsHeight) / 2 - ) + bounds.y - Math.max(20, (graph.container.clientHeight - boundsHeight) / 2) ) ); graph.container.scrollLeft = Math.floor( - Math.max( - 0, - bounds.x - - Math.max( - 0, - (graph.container.clientWidth - boundsWidth) / 2 - ) - ) + Math.max(0, bounds.x - Math.max(0, (graph.container.clientWidth - boundsWidth) / 2)) ); } } diff --git a/src/components/mxGraph/index.tsx b/src/components/mxGraph/index.tsx index bf021dc41..84911a91b 100644 --- a/src/components/mxGraph/index.tsx +++ b/src/components/mxGraph/index.tsx @@ -21,6 +21,7 @@ import { mxPopupMenuHandler, } from 'mxgraph'; import MxFactory from './factory'; +import useLocale from '../locale/useLocale'; const Mx = new MxFactory(); @@ -292,6 +293,8 @@ function MxGraphContainer( const keybindingsRef = useRef([]); const [current, setCurrent] = useState(null); + const locale = useLocale('MxGraph'); + useImperativeHandle(ref, () => ({ /** * 在某一位置插入节点 @@ -426,7 +429,7 @@ function MxGraphContainer( onGetPreview?.(node) || (() => { const dom = document.createElement('div'); - dom.innerHTML = `新节点`; + dom.innerHTML = `${locale.newNode}`; return dom; })(); diff --git a/src/components/notFound/index.tsx b/src/components/notFound/index.tsx index 97e9b9dc1..d920b7c12 100644 --- a/src/components/notFound/index.tsx +++ b/src/components/notFound/index.tsx @@ -1,15 +1,17 @@ import React from 'react'; import { FrownOutlined } from '@ant-design/icons'; +import useLocale from '../locale/useLocale'; -export default class NotFound extends React.Component { - render() { - return ( -
-

- 亲,是不是走错地方了? -

-
- ); - } -} +const NotFound = () => { + const locale = useLocale('NotFound'); + return ( +
+

+ {locale.description} +

+
+ ); +}; + +export default NotFound; diff --git a/src/components/progressLine/index.tsx b/src/components/progressLine/index.tsx index f2318d554..736967fdd 100644 --- a/src/components/progressLine/index.tsx +++ b/src/components/progressLine/index.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { Tooltip } from 'antd'; +import useLocale from '../locale/useLocale'; interface IProps { title?: string; @@ -12,7 +13,7 @@ interface IProps { } const ProgressLine = ({ - title = '暂无描述', + title, num = 0, percent = '0%', color = '#3BCEFF', @@ -21,7 +22,8 @@ const ProgressLine = ({ width = '280px', }: IProps) => { const slidePrefixCls = 'dtc-progress-line'; - const label = `${title}: ${num}`; + const locale = useLocale('ProgressLine'); + const label = `${title || locale.description}: ${num}`; return (
{needTitle && ( diff --git a/src/components/renderFormItem/index.tsx b/src/components/renderFormItem/index.tsx index f0ac55af2..1bdb48e1d 100644 --- a/src/components/renderFormItem/index.tsx +++ b/src/components/renderFormItem/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Form, Input } from 'antd'; import { Rule } from 'antd/lib/form'; +import useLocale from '../locale/useLocale'; const FormItem = Form.Item; @@ -10,7 +11,7 @@ interface ItemType { key: string | number | (string | number)[]; required?: boolean; component?: React.ReactNode; - tooltip?: React.ReactNode | string; + tooltip?: React.ReactNode; extra?: React.ReactNode; options?: { className?: string; @@ -43,6 +44,8 @@ export default function RenderFormItem({ item, layout }: ItemType) { valuePropName, normalize, } = options; + const locale = useLocale('RenderFormItem'); + return ( ; } export default class Resize extends React.Component { componentDidMount() { @@ -19,6 +19,6 @@ export default class Resize extends React.Component { }; render() { - return this.props.children; + return <>{this.props.children}; } } diff --git a/src/components/searchModal/index.tsx b/src/components/searchModal/index.tsx index 00de3cfaa..1bef1ea4a 100644 --- a/src/components/searchModal/index.tsx +++ b/src/components/searchModal/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Modal, AutoComplete, Input, Row, Col } from 'antd'; +import useLocale, { Locale } from '../locale/useLocale'; export interface SearchModalProps { visible: boolean; @@ -8,6 +9,7 @@ export interface SearchModalProps { title?: string | null; placeholder?: string; prefixRender?: React.ReactNode; + locale?: Locale['SearchModal']; onChange?: (value: string) => void; onSelect?: (value: string, option: Object) => void; onCancel?: () => void; @@ -30,15 +32,22 @@ class SearchModal extends React.Component { render() { const { visible, - title = '搜索并打开', + title, prefixRender, dataSource = [], // bodyStyle, - placeholder = '请输入', + placeholder, + locale, ...rest } = this.props; return ( - + {prefixRender && ( @@ -52,7 +61,7 @@ class SearchModal extends React.Component { onSelect={this.onSelect} onSearch={this.onChange} > - + @@ -60,4 +69,11 @@ class SearchModal extends React.Component { ); } } -export default SearchModal; + +const SearchModalWrapper = (props: Omit) => { + const locale = useLocale('SearchModal'); + const { visible, dataSource, ...reset } = props; + return ; +}; + +export default SearchModalWrapper; diff --git a/src/components/spreadSheet/index.tsx b/src/components/spreadSheet/index.tsx index f658fef74..cdb5b1128 100644 --- a/src/components/spreadSheet/index.tsx +++ b/src/components/spreadSheet/index.tsx @@ -2,46 +2,66 @@ import React from 'react'; import CopyUtils from '../utils/copy'; import { HotTable } from '@handsontable/react'; +import type { HotTableProps } from '@handsontable/react'; import classNames from 'classnames'; import 'handsontable/dist/handsontable.full.css'; import 'handsontable/languages/zh-CN.js'; +import useLocale, { Locale } from '../locale/useLocale'; + +type IOptions = HotTableProps & { + /** 是否展示复制值以及列名 */ + showCopyWithHeader?: boolean; +}; export interface SpreadSheetProps { - data: Array>; + data: Array>; columns: any; className?: string; + options?: IOptions; + /** 结果数据每一列的字段类型,由服务端返回 */ + columnTypes?: Array<{ + /** 字段名称 */ + name: string; + /** 字段类型 */ + type: string; + }>; + locale?: Locale['SpreadSheet']; + hotTableInstanceRef?: (instance: any) => void; } class SpreadSheet extends React.PureComponent { tableRef: any = React.createRef(); copyUtils = new CopyUtils(); - _renderColck: any; + _renderTimer: any; + + componentDidMount() { + this.props.hotTableInstanceRef?.(this.tableRef.current); + } componentDidUpdate(prevProps: any, _prevState: any) { if (prevProps != this.props) { if (this.tableRef) { this.removeRenderClock(); - this._renderColck = setTimeout(() => { - console.log('render sheet'); + this._renderTimer = setTimeout(() => { this.tableRef.current.hotInstance.render(); }, 100); } } } removeRenderClock() { - if (this._renderColck) { - clearTimeout(this._renderColck); + if (this._renderTimer) { + clearTimeout(this._renderTimer); } } componentWillUnmount() { this.removeRenderClock(); } getData() { - const { data, columns = [] } = this.props; + const { data, columns = [], locale } = this.props; let showData = data; if (!showData || !showData.length) { const emptyArr = new Array(columns.length).fill('', 0, columns.length); - emptyArr[0] = '暂无数据'; + emptyArr[0] = locale.description; showData = [emptyArr]; } return showData; @@ -74,22 +94,48 @@ class SpreadSheet extends React.PureComponent { } getContextMenu() { const that = this; - return { - items: { - copy: { - name: '复制', - callback: function () { - const indexArr = this.getSelected(); - // eslint-disable-next-line prefer-spread - const copyDataArr = this.getData.apply(this, indexArr[0]); - that.beforeCopy(copyDataArr); - }, + const { columns = [], options, locale } = this.props; + const items = { + copy: { + name: locale.copy, + callback: function (_key) { + const indexArr = this.getSelected(); + // eslint-disable-next-line prefer-spread + const copyDataArr = this.getData.apply(this, indexArr[0]); + that.beforeCopy(copyDataArr); }, }, + }; + if (options?.showCopyWithHeader) { + const copyWithHeaderItem = { + name: locale.copyAll, + callback: function (_key, selection) { + const indexArr = this.getSelected(); + // eslint-disable-next-line prefer-spread + let copyDataArr = this.getData.apply(this, indexArr[0]); + const columnStart = selection?.[0]?.start?.col; + const columnEnd = selection?.[0]?.end?.col; + let columnArr; + if (columnStart !== undefined && columnEnd !== undefined) { + columnArr = columns.slice(columnStart, columnEnd + 1); + } + if (columnArr) { + copyDataArr = [columnArr, ...copyDataArr]; + } + that.beforeCopy(copyDataArr); + }, + }; + // 目前版本不支持 copy_with_column_headers 暂时用 cut 代替,以达到与copy类似的表现 + items['cut'] = copyWithHeaderItem; + } + return { + items, } as any; } render() { - const { columns = [], className = '' } = this.props; + const { columns = [], className = '', options, columnTypes = [] } = this.props; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { trimWhitespace = true, showCopyWithHeader, ...restOptions } = options || {}; const showData = this.getData(); // 空数组情况,不显示colHeaders,否则colHeaders默认会按照 A、B...显示 // 具体可见 https://handsontable.com/docs/7.1.1/Options.html#colHeaders @@ -98,12 +144,22 @@ class SpreadSheet extends React.PureComponent { isShowColHeaders = true; } return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore { + if (!isShowColHeaders) return false; + // handsontable 不支持 renderCustomHeader,所以只能用 html string 实现 tooltip + const fieldTypeStr = columnTypes?.[index]?.type; + const title = fieldTypeStr + ? `${columns?.[index]}: ${fieldTypeStr}` + : columns?.[index]; + return `${title}`; + }} data={showData} mergeCells={this.getMergeCells()} cell={this.getCell()} @@ -113,12 +169,21 @@ class SpreadSheet extends React.PureComponent { manualRowResize // 拉伸功能 manualColumnResize // 拉伸功能 colWidths={200} + trimWhitespace={trimWhitespace} // false 表示不去除内容里的空格 beforeCopy={this.beforeCopy.bind(this)} + beforeCut={() => false} columnHeaderHeight={25} contextMenu={this.getContextMenu()} stretchH="all" // 填充空白区域 + {...restOptions} /> ); } } -export default SpreadSheet; + +const SpreadSheetWrapper = (props: Omit) => { + const locale = useLocale('SpreadSheet'); + return ; +}; + +export default SpreadSheetWrapper; diff --git a/src/components/statusTag/index.tsx b/src/components/statusTag/index.tsx index c79036475..958c2c784 100644 --- a/src/components/statusTag/index.tsx +++ b/src/components/statusTag/index.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; export type StatusTagType = 'warning' | 'error' | 'success' | 'run' | 'stopped'; -export interface StatusTagProps extends React.HTMLAttributes{ +export interface StatusTagProps extends React.HTMLAttributes { type?: StatusTagType; className?: string; showBorder?: boolean; diff --git a/src/components/textMark/index.tsx b/src/components/textMark/index.tsx index 6bc5a7eb5..224830017 100644 --- a/src/components/textMark/index.tsx +++ b/src/components/textMark/index.tsx @@ -7,7 +7,7 @@ export interface TextMarkProps { [propName: string]: any; } class TextMark extends React.Component { - renderMark(text = '', markText = ''): React.ReactNode | string { + renderMark(text = '', markText = ''): React.ReactNode { const markTextIndex = text.indexOf(markText); if (markTextIndex !== -1) { return ( diff --git a/src/components/toolModal/index.tsx b/src/components/toolModal/index.tsx index 942342bbd..5f7b56219 100644 --- a/src/components/toolModal/index.tsx +++ b/src/components/toolModal/index.tsx @@ -5,7 +5,7 @@ import Fullscreen from '../fullscreen'; export interface ToolModalProps { visible: boolean; - toolbox?: React.ReactNode | string; + toolbox?: React.ReactNode; fullscreen?: boolean | undefined; [propName: string]: any; } diff --git a/src/stories/blockHeader.stories.tsx b/src/stories/blockHeader.stories.tsx index ebb6581eb..b78fd517f 100644 --- a/src/stories/blockHeader.stories.tsx +++ b/src/stories/blockHeader.stories.tsx @@ -10,7 +10,7 @@ stories.addDecorator(withKnobs); const propDefinitions = [ { property: 'title', - propType: 'string', + propType: 'React.ReactNode', required: true, description: '标题', defaultValue: '-', @@ -71,6 +71,20 @@ const propDefinitions = [ description: '是否默认展开内容', defaultValue: 'true', }, + { + property: 'hasBottom', + propType: 'boolean', + required: false, + description: '是否有默认下边距16px', + defaultValue: 'false', + }, + { + property: 'spaceBottom', + propType: 'number', + required: false, + description: '自定义下边距,优先级高于 hasBottom', + defaultValue: 0, + }, { property: 'children', propType: 'React.ReactNode', @@ -122,6 +136,10 @@ stories.add( console.log(expand)}> Hello World! +

7、标题超长

+ } /> +
+

大标题 + 无背景

1、默认

@@ -145,6 +163,7 @@ stories.add( > Hello World! +

小标题

小标题 + 有背景

1、默认

@@ -169,6 +188,8 @@ stories.add( > Hello World!
+
+

小标题 + 无背景

1、默认

diff --git a/src/stories/components/blockHeader/index.tsx b/src/stories/components/blockHeader/index.tsx index 7bee9c30b..53f53db59 100644 --- a/src/stories/components/blockHeader/index.tsx +++ b/src/stories/components/blockHeader/index.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { PieChartOutlined } from '@ant-design/icons'; import BlockHeader from '../../../components/blockHeader'; +import EllipsisText from '../../../components/ellipsisText'; +import { Button } from 'antd'; export default function BlockHeaderRender() { const style = { @@ -28,6 +30,30 @@ export default function BlockHeaderRender() { console.log(expand)}> Hello World! +

7、标题超长

+ + } + /> +

8、标题超长且有 afterTitle

+
+ + } + afterTitle="这是 afterTitle" + addonAfter={} + /> +
+
+

大标题 + 无背景

1、默认

@@ -51,6 +77,7 @@ export default function BlockHeaderRender() { > Hello World! +

小标题

小标题 + 有背景

1、默认

@@ -68,13 +95,11 @@ export default function BlockHeaderRender() {

5、简洁版

6、展开/收起内容

- console.log(expand)} - > + console.log(expand)}> Hello World! +
+

小标题 + 无背景

1、默认

diff --git a/src/stories/ellipsisText.stories.tsx b/src/stories/ellipsisText.stories.tsx index ac80a339d..eea9bf994 100644 --- a/src/stories/ellipsisText.stories.tsx +++ b/src/stories/ellipsisText.stories.tsx @@ -59,14 +59,15 @@ stories.add(

何时使用

- 对长文本内容显示做一定限制,根据最近块级父元素自动计算最大宽度,也可以手动传最大宽度,hover + 用于长文本省略,根据最近块级父元素自动计算文本最大宽度,也可以手动传最大宽度,当传入maxWidth时不会去动态计算文本宽度,hover 显示完整内容。

  • 自动计算宽度仅限于最近块级父元素下都为行内元素
  • 如果最近块级元素为行内块级元素,必须设置宽度
  • 使用antd table当表头fixed:true时,请传maxWidth
  • -
  • 使用多个EllipsisText最好传maxWidth
  • +
  • 某个元素下使用多个EllipsisText最好传maxWidth
  • +
  • 大批量数据使用时最好传maxWidth,防止出现性能问题

示例

场景一: @@ -96,7 +97,7 @@ stories.add( value={'我是很长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长的文本'} maxWidth={200} /> - +
场景二(请更改窗口大小): {
diff --git a/tsconfig.json b/tsconfig.json index 6a9fcbfe7..62e019bd8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,7 @@ "lib", "storybook-static", "src/public/**/*", + "src/stories/*", "./gulpfile.js" ], "include": ["./**/*.ts", "./**/*.tsx", "src/**/*", "gulpfile.js"] diff --git a/yarn.lock b/yarn.lock index 9295090ef..34ff61ecb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2326,18 +2326,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@handsontable/formulajs@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@handsontable/formulajs/-/formulajs-2.0.2.tgz#5be4b9226cc47811f646ae46b1b985230cd82995" - integrity sha512-maIyMJtYjA5e/R9nyA22Qd7Yw73MBSxClJvle0a8XWAS/5l6shc/OFpQqrmwMy4IXUCmywJ9ER0gOGz/YA720w== - dependencies: - bessel "^1.0.2" - jstat "^1.9.2" - -"@handsontable/react@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@handsontable/react/-/react-3.0.0.tgz#70fb0b359b4672eb3da1d70000b26950c7b2e1e1" - integrity sha512-SAN2t9w5qx8o86qpdW6OixT2Rl1MLUPzVsBLiVqHbxKxQnGqGFXMI3J/xtO1gBCL3DsrRbonid90WgvNFl86cw== +"@handsontable/react@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@handsontable/react/-/react-2.1.0.tgz#3b87ebfc0d5d47e1b0d07856bd473017a0a7179f" + integrity sha512-Du73MFU2y1Bfe9m7mvxY70lB2R/VigFSpOwWZjDnUt/HwNPbNr+UQcY40w6u7acllQeee45H7jRdEExzsrvDKw== "@humanwhocodes/config-array@^0.10.4", "@humanwhocodes/config-array@^0.10.5": version "0.10.7" @@ -4139,13 +4131,12 @@ expect "^28.0.0" pretty-format "^28.0.0" -"@types/jest@^26.0.9": - version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" - integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== +"@types/jest@^24.9.1": + version "24.9.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.1.tgz#02baf9573c78f1b9974a5f36778b366aa77bd534" + integrity sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q== dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" + jest-diff "^24.3.0" "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.11" @@ -4192,13 +4183,6 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/pikaday@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@types/pikaday/-/pikaday-1.6.0.tgz#46c1d67a9ef706284ac2b72bf31bf381a56bf3c0" - integrity sha512-cnKjF7i6oA1ADxQdSWHcEStLZeiH8qbf6l7B9O88PhLgnmbUMM62ali0/PaDtINm6ezpNcqtERWL6Y+pAgHKQQ== - dependencies: - moment ">=2.14.0" - "@types/prop-types@*": version "15.7.5" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" @@ -4245,7 +4229,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.0.17": +"@types/react@*": version "18.0.17" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.17.tgz#4583d9c322d67efe4b39a935d223edcc7050ccf4" integrity sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ== @@ -4254,6 +4238,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^16.14.28": + version "16.14.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.37.tgz#46bab00eee7829e7551ec8d7d1b12afd5de84a87" + integrity sha512-Jy/9txct4JC2nQsJNACeFczzIQ2Bh7s1PZpbYMs9jbj/jREWxEH0qGFYYZb7dq7H1sU0AAzHAPevtxBHGk6N6Q== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" @@ -6220,20 +6213,15 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bessel@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bessel/-/bessel-1.0.2.tgz#828812291e0b62e94959cdea43fac186e8a7202d" - integrity sha512-Al3nHGQGqDYqqinXhQzmwmcRToe/3WyBv4N8aZc5Pef8xw2neZlR9VPi84Sa23JtgWcucu18HxVZrnI0fn2etw== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bignumber.js@^4.0.4: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" - integrity sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA== +bignumber.js@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.1.1.tgz#4b072ae5aea9c20f6730e4e5d529df1271c4d885" + integrity sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ== binary-extensions@^1.0.0: version "1.13.1" @@ -7605,11 +7593,6 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-js@^3.0.0: - version "3.25.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.25.3.tgz#cbc2be50b5ddfa7981837bd8c41639f27b166593" - integrity sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ== - core-js@^3.0.1, core-js@^3.0.4, core-js@^3.8.2: version "3.24.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f" @@ -8078,9 +8061,9 @@ decimal.js@^10.2.1: integrity sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg== decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== dedent@0.7.0: version "0.7.0" @@ -8271,11 +8254,6 @@ diff-sequences@^24.9.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - diff-sequences@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" @@ -10671,16 +10649,13 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -handsontable@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/handsontable/-/handsontable-7.0.1.tgz#c9e12be4faddae161782feb9559e4de707ffefb2" - integrity sha512-0vf4rXliqtuN6VHA/Ov+7I3PmxPAoVn96sUxfFnPODv8l9NQIfnYHrT2jdQBAPtwIYPzFlFgavT1Su7vCK3QmA== +handsontable@6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/handsontable/-/handsontable-6.2.2.tgz#f1250f3f374abdf7d4a0080950482d3edeea8f07" + integrity sha512-Z/sQa51OMHH4RoeBJeANYJMJYmx5SR+/xP8JCh5mzKJnAMKoQWF1zONPNgNCFZ/LdKFmI0f34XKtU0GHW0MG/Q== dependencies: - "@types/pikaday" "1.6.0" - core-js "^3.0.0" - hot-formula-parser "^3.0.0" moment "2.20.1" - numbro "2.1.1" + numbro "^2.0.6" pikaday "1.5.1" har-schema@^2.0.0: @@ -10916,14 +10891,6 @@ hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: dependencies: lru-cache "^6.0.0" -hot-formula-parser@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/hot-formula-parser/-/hot-formula-parser-3.0.2.tgz#d71f03a4ef43ba3074bde383a0e36202b5b64116" - integrity sha512-W/Dj/UbIyuViMIQOQD6tUEVySl7jd6ei+gfWslTiRqa4yRhkyHnIz8N4oLnqgDRhhVAQIcFF5NfNz49k4X8IxQ== - dependencies: - "@handsontable/formulajs" "^2.0.2" - tiny-emitter "^2.1.0" - html-element-map@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.3.1.tgz#44b2cbcfa7be7aa4ff59779e47e51012e1c73c08" @@ -12087,7 +12054,7 @@ jest-config@^24.9.0: pretty-format "^24.9.0" realpath-native "^1.1.0" -jest-diff@^24.9.0: +jest-diff@^24.3.0, jest-diff@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== @@ -12097,16 +12064,6 @@ jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-diff@^26.0.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - jest-diff@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" @@ -12173,11 +12130,6 @@ jest-get-type@^24.9.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - jest-get-type@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" @@ -12794,11 +12746,6 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -jstat@^1.9.2: - version "1.9.5" - resolved "https://registry.yarnpkg.com/jstat/-/jstat-1.9.5.tgz#9941741566f683624ddeb56f5ba60ed8c29b374e" - integrity sha512-cWnp4vObF5GmB2XsIEzxI/1ZTcYlcfNqxQ/9Fp5KFUa0Jf/4tO0ZkGVnqoEHDisJvYgvn5n3eWZbd2xTVJJPUQ== - jstransform@^11.0.3: version "11.0.3" resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-11.0.3.tgz#09a78993e0ae4d4ef4487f6155a91f6190cb4223" @@ -12873,10 +12820,10 @@ known-css-properties@^0.25.0: resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776" integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA== -ko-lint-config@^2.2.15: - version "2.2.15" - resolved "https://registry.yarnpkg.com/ko-lint-config/-/ko-lint-config-2.2.15.tgz#9f2f18be6decfbe68350e79dce5780397dfa4983" - integrity sha512-mn5IG+ULF+oEaQ1NlknxW3Le6B20RYmLJ8fYPUQjppVfBeEqEyFzh6gsngvZFg1/M6StV5g7xnPwH2Tolp2kCg== +ko-lint-config@2.2.19: + version "2.2.19" + resolved "https://registry.npmmirror.com/ko-lint-config/-/ko-lint-config-2.2.19.tgz#23141b8d8bbbb155b4f6113f894df5e5ea9a0741" + integrity sha512-EMdRaxNXXFe90Q2JQNIJeHSRMn1y5LKNrrGVTwRVWvk/jnP3UQ411K4petpATbgkjU36YEDBa6Y3LVXk8asB+Q== dependencies: "@typescript-eslint/eslint-plugin" "5.30.0" "@typescript-eslint/parser" "5.30.0" @@ -13874,7 +13821,7 @@ moment@2.20.1: resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" integrity sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg== -moment@2.x, moment@>=2.14.0, moment@^2.22.2, moment@^2.24.0, moment@^2.29.2: +moment@2.x, moment@^2.22.2, moment@^2.24.0, moment@^2.29.2: version "2.29.4" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== @@ -14262,12 +14209,12 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -numbro@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.1.1.tgz#b977fc6a769163f90e2e2d7623ff9db4d66bc661" - integrity sha512-H3VamlHyqYYomNngAbrl/CT92DnOSC2rJxx6hfZrgj0NVnqxAtOvGbwgpOYjv4ASgxodDWBSYHJ1ZxaEq2lfTg== +numbro@^2.0.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.3.6.tgz#4bd622ebe59ccbc49dad365c5b9eed200781fa21" + integrity sha512-pxpoTT3hVxQGaOA2RTzXR/muonQNd1K1HPJbWo7QOmxPwiPmoFCFfsG9XXgW3uqjyzezJ0P9IvCPDXUtJexjwg== dependencies: - bignumber.js "^4.0.4" + bignumber.js "^8.1.1" nwsapi@^2.0.7: version "2.2.1" @@ -15261,7 +15208,7 @@ pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" -pretty-format@^26.0.0, pretty-format@^26.6.2: +pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== @@ -16443,10 +16390,10 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@16.13.0: - version "16.13.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.13.0.tgz#d046eabcdf64e457bbeed1e792e235e1b9934cf7" - integrity sha512-TSavZz2iSLkq5/oiE7gnFzmURKZMltmi193rm5HEoUDAXpzT9Kzw6oNZnGoai/4+fUnm7FqS5dwgUL34TujcWQ== +react@16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" + integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -18567,7 +18514,7 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tiny-emitter@^2.0.0, tiny-emitter@^2.1.0: +tiny-emitter@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== @@ -18925,9 +18872,9 @@ typescript@~4.5.2: integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== ua-parser-js@^0.7.30, ua-parser-js@^0.7.9: - version "0.7.31" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" - integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== uglify-js@3.4.x: version "3.4.10"