From aff559882fcc8ef1e11aaa3a0ae963d052c4eaca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=AB=E9=9B=A8=E6=B0=B4=E8=BF=87=E6=BB=A4=E7=9A=84?= =?UTF-8?q?=E7=A9=BA=E6=B0=94-Rain?= <958414905@qq.com> Date: Mon, 4 Sep 2023 16:25:49 +0800 Subject: [PATCH] fix(RangePicker): fix shortcut invalid (#2586) * chore: upgrade antd to v5.8.4 * test: add test * chore: fix build * chore: upgrade @formily/antd-v5 to v1.1.1 * fix: should not close Popover when selected option * fix: add a new Popover and to replace old Popover with new Popover * refactor: remove useless code * fix: fix dark theme * chore: fix build * chore: antd version * fix: uniformly use the latest version of antd --- package.json | 3 +- packages/core/client/package.json | 8 +- .../templates/components/PreviewFields.tsx | 4 +- packages/core/client/src/global-theme/type.ts | 2 +- packages/core/client/src/pm/style.ts | 3 + .../schema-component/antd/action/Action.tsx | 3 +- .../InternalPopoverNester.tsx | 8 +- .../__tests__/date-picker.test.tsx | 42 +++- .../antd/date-picker/demos/demo11.tsx | 65 +++++ .../antd/filter/FilterAction.tsx | 13 +- .../antd/icon-picker/IconPicker.tsx | 3 +- .../client/src/schema-component/antd/index.ts | 1 + .../antd/input/EllipsisWithTooltip.tsx | 4 +- .../src/schema-component/antd/page/style.ts | 3 + .../schema-component/antd/popover/Popover.tsx | 16 ++ .../schema-component/antd/popover/index.ts | 1 + .../antd/quick-edit/QuickEdit.tsx | 2 +- .../charts/src/client/select/CustomSelect.tsx | 16 +- .../src/client/GraphDrawPage.tsx | 11 +- .../src/client/components/Entity.tsx | 7 +- .../src/client/Localization.tsx | 3 +- packages/plugins/mobile-client/package.json | 2 +- .../token-panel-pro/TokenContent.tsx | 10 +- yarn.lock | 229 +++++++++++------- 24 files changed, 323 insertions(+), 136 deletions(-) create mode 100644 packages/core/client/src/schema-component/antd/date-picker/demos/demo11.tsx create mode 100644 packages/core/client/src/schema-component/antd/popover/Popover.tsx create mode 100644 packages/core/client/src/schema-component/antd/popover/index.ts diff --git a/package.json b/package.json index 7ca10425b1..4a77e50132 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,8 @@ "react-router-dom": "^6.11.2", "react-router": "^6.11.2", "react": "^18.0.0", - "react-dom": "^18.0.0" + "react-dom": "^18.0.0", + "antd": "5.8.6" }, "config": { "ghooks": { diff --git a/packages/core/client/package.json b/packages/core/client/package.json index ebf716aa9a..fae992244a 100644 --- a/packages/core/client/package.json +++ b/packages/core/client/package.json @@ -8,14 +8,14 @@ "dependencies": { "@ant-design/cssinjs": "^1.11.1", "@ant-design/icons": "^5.1.4", - "@ant-design/pro-layout": "^7.14.3", + "@ant-design/pro-layout": "^7.16.11", "@antv/g2plot": "^2.4.18", "@ctrl/tinycolor": "^3.6.0", "@dnd-kit/core": "^5.0.1", "@dnd-kit/modifiers": "^6.0.0", "@dnd-kit/sortable": "^6.0.0", "@emotion/css": "^11.7.1", - "@formily/antd-v5": "^1.1.0", + "@formily/antd-v5": "1.1.1", "@formily/core": "^2.2.27", "@formily/grid": "^2.2.27", "@formily/json-schema": "^2.2.27", @@ -30,8 +30,8 @@ "@nocobase/utils": "0.13.0-alpha.5", "@types/requirejs": "^2.1.34", "ahooks": "^3.7.2", - "antd": "^5.7.3", - "antd-style": "^3.3.0", + "antd": "5.8.6", + "antd-style": "3.x", "axios": "^0.26.1", "classnames": "^2.3.1", "cron-parser": "^4.6.0", diff --git a/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx b/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx index e6a7dc0cd0..09d063f07a 100644 --- a/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx +++ b/packages/core/client/src/collection-manager/templates/components/PreviewFields.tsx @@ -1,8 +1,6 @@ -import { Cascader } from '@formily/antd-v5'; import { useField, useForm } from '@formily/react'; -import { Input, Select, Spin, Table, Tag } from 'antd'; +import { Cascader, Input, Select, Spin, Table, Tag } from 'antd'; import { last } from 'lodash'; -import { boolean } from 'mathjs'; import React, { useContext, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ResourceActionContext, useCompile } from '../../../'; diff --git a/packages/core/client/src/global-theme/type.ts b/packages/core/client/src/global-theme/type.ts index 014de53441..40779b727d 100644 --- a/packages/core/client/src/global-theme/type.ts +++ b/packages/core/client/src/global-theme/type.ts @@ -1,4 +1,4 @@ -import { MappingAlgorithm } from 'antd/es/config-provider/context'; +import { MappingAlgorithm } from 'antd-style'; import { OverrideToken } from 'antd/es/theme/interface'; import { AliasToken } from 'antd/es/theme/internal'; diff --git a/packages/core/client/src/pm/style.ts b/packages/core/client/src/pm/style.ts index 5d5790b18e..dc1ddd4167 100644 --- a/packages/core/client/src/pm/style.ts +++ b/packages/core/client/src/pm/style.ts @@ -11,6 +11,9 @@ export const useStyles = createStyles(({ token }) => { '& .ant-tabs-nav': { marginBottom: 0, }, + '.ant-page-header-heading-title': { + color: token.colorText, + }, }, pageContent: { diff --git a/packages/core/client/src/schema-component/antd/action/Action.tsx b/packages/core/client/src/schema-component/antd/action/Action.tsx index 1f75d11c65..bcea781d6a 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -1,5 +1,5 @@ import { observer, RecursionField, useField, useFieldSchema, useForm } from '@formily/react'; -import { App, Button, Popover } from 'antd'; +import { App, Button } from 'antd'; import classnames from 'classnames'; import lodash from 'lodash'; import React, { useEffect, useState } from 'react'; @@ -11,6 +11,7 @@ import { useRecord } from '../../../record-provider'; import { SortableItem } from '../../common'; import { useCompile, useComponent, useDesigner } from '../../hooks'; import { useProps } from '../../hooks/useProps'; +import { Popover } from '../popover'; import ActionContainer from './Action.Container'; import { ActionDesigner } from './Action.Designer'; import { ActionDrawer } from './Action.Drawer'; diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalPopoverNester.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalPopoverNester.tsx index ec090f5c91..7b68398587 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalPopoverNester.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalPopoverNester.tsx @@ -1,13 +1,13 @@ -import { Popover } from 'antd'; -import { css } from '@emotion/css'; import { EditOutlined } from '@ant-design/icons'; +import { css } from '@emotion/css'; import { observer } from '@formily/react'; import React, { useContext, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ReadPrettyInternalViewer } from './InternalViewer'; +import { ActionContext, ActionContextProvider } from '../action/context'; +import { Popover } from '../popover'; import { InternalNester } from './InternalNester'; +import { ReadPrettyInternalViewer } from './InternalViewer'; import { useAssociationFieldContext } from './hooks'; -import { ActionContextProvider, ActionContext } from '../action/context'; export const InternaPopoverNester = observer( (props) => { diff --git a/packages/core/client/src/schema-component/antd/date-picker/__tests__/date-picker.test.tsx b/packages/core/client/src/schema-component/antd/date-picker/__tests__/date-picker.test.tsx index 95ab97a60e..6f9a07d020 100644 --- a/packages/core/client/src/schema-component/antd/date-picker/__tests__/date-picker.test.tsx +++ b/packages/core/client/src/schema-component/antd/date-picker/__tests__/date-picker.test.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen, sleep, userEvent, waitFor } from 'testUtils'; import App1 from '../demos/demo1'; +import App11 from '../demos/demo11'; import App2 from '../demos/demo2'; import App3 from '../demos/demo3'; import App4 from '../demos/demo4'; @@ -68,8 +69,11 @@ describe('DatePicker', () => { await userEvent.click(picker); await userEvent.type(input, '2023/05/01'); - const selected = document.querySelector('.ant-picker-cell-selected') as HTMLElement; - expect(selected).toBeInTheDocument(); + let selected; + await waitFor(() => { + selected = document.querySelector('.ant-picker-cell-selected') as HTMLElement; + expect(selected).toBeInTheDocument(); + }); await userEvent.click(selected); expect(input).toHaveValue('2023/05/01'); @@ -138,15 +142,20 @@ describe('RangePicker', () => { const endInput = getByPlaceholderText('End date'); await userEvent.click(picker); + await sleep(); await userEvent.click(document.querySelector('[title="2023-05-01"]') as HTMLElement); await userEvent.click(document.querySelector('[title="2023-05-02"]') as HTMLElement); - expect(startInput).toHaveValue('2023-05-01'); - expect(endInput).toHaveValue('2023-05-02'); + await waitFor(() => expect(startInput).toHaveValue('2023-05-01')); + await waitFor(() => expect(endInput).toHaveValue('2023-05-02')); + // Read pretty - expect(screen.getByText('2023-05-01~2023-05-02', { selector: '.ant-description-text' })).toBeInTheDocument(); + await waitFor(() => + expect(screen.getByText('2023-05-01~2023-05-02', { selector: '.ant-description-text' })).toBeInTheDocument(), + ); + // Value - expect(screen.getByText('2023-05-01 ~ 2023-05-02')).toBeInTheDocument(); + await waitFor(() => expect(screen.getByText('2023-05-01 ~ 2023-05-02')).toBeInTheDocument()); }); it('showTime=false,gmt=true,utc=true', async () => { @@ -219,4 +228,25 @@ describe('RangePicker', () => { expect(screen.getByText(`${currentDateString}T00:00:00.000Z`)).toBeInTheDocument(); }); }); + + // fix T-1506 + it('shortcut', async () => { + const { container } = render(); + + await sleep(); + + const picker = container.querySelector('.ant-picker') as HTMLElement; + const startInput = screen.getByPlaceholderText('Start date'); + const endInput = screen.getByPlaceholderText('End date'); + + await userEvent.click(picker); + + // shortcut: Today + await userEvent.click(screen.getByText(/today/i)); + await sleep(); + + // 因为 Today 快捷键的值是动态生成的,所以这里没有断言具体的值 + await waitFor(() => expect(startInput.getAttribute('value')).toBeTruthy()); + await waitFor(() => expect(endInput.getAttribute('value')).toBeTruthy()); + }); }); diff --git a/packages/core/client/src/schema-component/antd/date-picker/demos/demo11.tsx b/packages/core/client/src/schema-component/antd/date-picker/demos/demo11.tsx new file mode 100644 index 0000000000..1cd60ac4d6 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/date-picker/demos/demo11.tsx @@ -0,0 +1,65 @@ +/** + * title: DatePicker.RangePicker + */ +import { FormItem } from '@formily/antd-v5'; +import { DatePicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; +import React from 'react'; + +const schema = { + type: 'object', + properties: { + input: { + type: 'boolean', + title: `Editable`, + 'x-decorator': 'FormItem', + 'x-component': 'DatePicker.RangePicker', + 'x-component-props': { + gmt: true, + }, + 'x-reactions': [ + { + target: 'read1', + fulfill: { + state: { + value: '{{$self.value}}', + }, + }, + }, + { + target: 'read2', + fulfill: { + state: { + value: '{{$self.value && $self.value.join(" ~ ")}}', + }, + }, + }, + ], + }, + read1: { + type: 'boolean', + title: `Read pretty`, + 'x-read-pretty': true, + 'x-decorator': 'FormItem', + 'x-component': 'DatePicker.RangePicker', + 'x-component-props': { + gmt: true, + }, + }, + read2: { + type: 'string', + title: `Value`, + 'x-read-pretty': true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + 'x-component-props': {}, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; diff --git a/packages/core/client/src/schema-component/antd/filter/FilterAction.tsx b/packages/core/client/src/schema-component/antd/filter/FilterAction.tsx index 2faac33c20..2edc93f6a5 100644 --- a/packages/core/client/src/schema-component/antd/filter/FilterAction.tsx +++ b/packages/core/client/src/schema-component/antd/filter/FilterAction.tsx @@ -1,13 +1,14 @@ import { css } from '@emotion/css'; import { createForm, Field, Form } from '@formily/core'; import { observer, useField, useFieldSchema, useForm } from '@formily/react'; -import { Button, Popover, Space } from 'antd'; -import React, { createContext, useContext, useMemo, useState } from 'react'; +import { Button, Space } from 'antd'; +import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FormProvider, SchemaComponent } from '../../core'; import { useDesignable } from '../../hooks'; import { useProps } from '../../hooks/useProps'; import { Action } from '../action'; +import { Popover } from '../popover'; export const FilterActionContext = createContext(null); @@ -20,15 +21,17 @@ export const FilterAction = observer( const fieldSchema = useFieldSchema(); const form = useMemo
(() => props.form || createForm(), []); const { options, onSubmit, onReset, ...others } = useProps(props); + const onOpenChange = useCallback((visible: boolean): void => { + setVisible(visible); + }, []); + return ( { - setVisible(visible); - }} + onOpenChange={onOpenChange} trigger={'click'} content={ diff --git a/packages/core/client/src/schema-component/antd/icon-picker/IconPicker.tsx b/packages/core/client/src/schema-component/antd/icon-picker/IconPicker.tsx index 71bafad26f..1062bc4cd9 100644 --- a/packages/core/client/src/schema-component/antd/icon-picker/IconPicker.tsx +++ b/packages/core/client/src/schema-component/antd/icon-picker/IconPicker.tsx @@ -2,10 +2,11 @@ import { CloseOutlined, LoadingOutlined } from '@ant-design/icons'; import { useFormLayout } from '@formily/antd-v5'; import { connect, mapProps, mapReadPretty } from '@formily/react'; import { isValid } from '@formily/shared'; -import { Button, Input, Popover } from 'antd'; +import { Button, Input } from 'antd'; import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Icon, hasIcon, icons } from '../../../icon'; +import { Popover } from '../popover'; function IconField(props: any) { const layout = useFormLayout(); diff --git a/packages/core/client/src/schema-component/antd/index.ts b/packages/core/client/src/schema-component/antd/index.ts index fd5b21bc48..a135753b3b 100644 --- a/packages/core/client/src/schema-component/antd/index.ts +++ b/packages/core/client/src/schema-component/antd/index.ts @@ -35,6 +35,7 @@ export * from './page'; export * from './pagination'; export * from './password'; export * from './percent'; +export * from './popover'; export * from './preview'; export * from './quick-edit'; export * from './radio'; diff --git a/packages/core/client/src/schema-component/antd/input/EllipsisWithTooltip.tsx b/packages/core/client/src/schema-component/antd/input/EllipsisWithTooltip.tsx index 408b66a930..9f97c597b7 100644 --- a/packages/core/client/src/schema-component/antd/input/EllipsisWithTooltip.tsx +++ b/packages/core/client/src/schema-component/antd/input/EllipsisWithTooltip.tsx @@ -1,5 +1,5 @@ -import { Popover } from 'antd'; -import React, { CSSProperties, forwardRef, useImperativeHandle, useState, useRef } from 'react'; +import React, { CSSProperties, forwardRef, useImperativeHandle, useRef, useState } from 'react'; +import { Popover } from '../popover'; const getContentWidth = (element) => { if (element) { diff --git a/packages/core/client/src/schema-component/antd/page/style.ts b/packages/core/client/src/schema-component/antd/page/style.ts index 75687a0e93..67d6e08387 100644 --- a/packages/core/client/src/schema-component/antd/page/style.ts +++ b/packages/core/client/src/schema-component/antd/page/style.ts @@ -49,6 +49,9 @@ export const useStyles = genStyleHook('nb-page', (token) => { '.ant-page-header-footer': { marginBlockStart: '0' }, }, '.ant-tabs-nav': { marginBottom: '0' }, + '.ant-page-header-heading-title': { + color: token.colorText, + }, }, '.height0': { diff --git a/packages/core/client/src/schema-component/antd/popover/Popover.tsx b/packages/core/client/src/schema-component/antd/popover/Popover.tsx new file mode 100644 index 0000000000..43fb91db35 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/popover/Popover.tsx @@ -0,0 +1,16 @@ +import { Popover as AntdPopover, PopoverProps } from 'antd'; +import React, { useCallback } from 'react'; + +export const Popover = (props: PopoverProps) => { + // 参见:https://github.com/ant-design/ant-design/issues/44119 + // fix T-1508 + const avoidClose = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); + }, []); + + return ( +
+ +
+ ); +}; diff --git a/packages/core/client/src/schema-component/antd/popover/index.ts b/packages/core/client/src/schema-component/antd/popover/index.ts new file mode 100644 index 0000000000..8f473de4b9 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/popover/index.ts @@ -0,0 +1 @@ +export * from './Popover'; diff --git a/packages/core/client/src/schema-component/antd/quick-edit/QuickEdit.tsx b/packages/core/client/src/schema-component/antd/quick-edit/QuickEdit.tsx index ed5de34057..e526a9fd43 100644 --- a/packages/core/client/src/schema-component/antd/quick-edit/QuickEdit.tsx +++ b/packages/core/client/src/schema-component/antd/quick-edit/QuickEdit.tsx @@ -2,9 +2,9 @@ import { css } from '@emotion/css'; import { FormItem } from '@formily/antd-v5'; import { Field, createForm } from '@formily/core'; import { FormContext, RecursionField, observer, useField, useFieldSchema } from '@formily/react'; -import { Popover } from 'antd'; import React, { useMemo, useRef } from 'react'; import { useCollectionManager } from '../../../collection-manager'; +import { Popover } from '../popover'; export const Editable = observer((props) => { const field: any = useField(); diff --git a/packages/plugins/charts/src/client/select/CustomSelect.tsx b/packages/plugins/charts/src/client/select/CustomSelect.tsx index 7061682b55..1e5c364f83 100644 --- a/packages/plugins/charts/src/client/select/CustomSelect.tsx +++ b/packages/plugins/charts/src/client/select/CustomSelect.tsx @@ -1,9 +1,9 @@ import { LoadingOutlined } from '@ant-design/icons'; import { connect, mapProps, mapReadPretty } from '@formily/react'; import { isValid } from '@formily/shared'; -import { css, Icon } from '@nocobase/client'; +import { Icon, Popover, css } from '@nocobase/client'; import type { SelectProps } from 'antd'; -import { Popover, Select as AntdSelect } from 'antd'; +import { Select as AntdSelect } from 'antd'; import React from 'react'; import { lang } from '../locale'; import { ReadPretty } from './ReadPretty'; @@ -35,7 +35,7 @@ const InternalSelect = connect( > {group1.map((option) => ( - {group2.map((option) => ( -