mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 14:46:13 +00:00
feat: add useNiceDropdownMaxHeight
This commit is contained in:
parent
e7e47f90fd
commit
9fdd88c479
@ -3,6 +3,7 @@ import { ConfigProvider, Popover, theme } from 'antd';
|
|||||||
import React, { ComponentType, useCallback, useMemo, useState } from 'react';
|
import React, { ComponentType, useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
import { useNiceDropdownMaxHeight } from '../../../common/useNiceDropdownHeight';
|
||||||
import { useFlag } from '../../../flag-provider';
|
import { useFlag } from '../../../flag-provider';
|
||||||
import { useDesignable } from '../../../schema-component';
|
import { useDesignable } from '../../../schema-component';
|
||||||
import { useSchemaInitializerStyles } from '../components/style';
|
import { useSchemaInitializerStyles } from '../components/style';
|
||||||
@ -45,6 +46,7 @@ export function withInitializer<T>(C: ComponentType<T>) {
|
|||||||
const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
|
const { wrapSSR, hashId, componentCls } = useSchemaInitializerStyles();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
|
||||||
|
|
||||||
const cProps = useMemo(
|
const cProps = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -90,9 +92,8 @@ export function withInitializer<T>(C: ComponentType<T>) {
|
|||||||
<div
|
<div
|
||||||
className={`${componentCls} ${hashId}`}
|
className={`${componentCls} ${hashId}`}
|
||||||
style={{
|
style={{
|
||||||
maxHeight: 'calc(50vh - 50px)',
|
maxHeight: dropdownMaxHeight,
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
overflowX: 'hidden',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
|
30
packages/core/client/src/common/useNiceDropdownHeight.ts
Normal file
30
packages/core/client/src/common/useNiceDropdownHeight.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过鼠标的位置计算出最佳的 dropdown 的高度,以尽量避免出现滚动条
|
||||||
|
* @param deps 类似于 useEffect 的第二个参数,如果不传则默认为 []
|
||||||
|
*/
|
||||||
|
export const useNiceDropdownMaxHeight = (deps: any[] = []) => {
|
||||||
|
const [maxHeight, setMaxHeight] = useState(0);
|
||||||
|
const heightRef = useRef(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e: MouseEvent) => {
|
||||||
|
const { clientY } = e;
|
||||||
|
const h = Math.max(clientY, window.innerHeight - clientY);
|
||||||
|
heightRef.current = h;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', handler);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('mousemove', handler);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMaxHeight(heightRef.current);
|
||||||
|
}, deps);
|
||||||
|
|
||||||
|
return maxHeight - 40;
|
||||||
|
};
|
@ -76,6 +76,7 @@ import {
|
|||||||
} from '../block-provider/hooks';
|
} from '../block-provider/hooks';
|
||||||
import { useCollectionFilterOptionsV2 } from '../collection-manager/action-hooks';
|
import { useCollectionFilterOptionsV2 } from '../collection-manager/action-hooks';
|
||||||
import { SelectWithTitle, SelectWithTitleProps } from '../common/SelectWithTitle';
|
import { SelectWithTitle, SelectWithTitleProps } from '../common/SelectWithTitle';
|
||||||
|
import { useNiceDropdownMaxHeight } from '../common/useNiceDropdownHeight';
|
||||||
import {
|
import {
|
||||||
FilterBlockType,
|
FilterBlockType,
|
||||||
getSupportFieldsByAssociation,
|
getSupportFieldsByAssociation,
|
||||||
@ -156,12 +157,9 @@ export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) =>
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { Component, getMenuItems } = useMenuItem();
|
const { Component, getMenuItems } = useMenuItem();
|
||||||
const [, startTransition] = useReactTransition();
|
const [, startTransition] = useReactTransition();
|
||||||
|
const dropdownMaxHeight = useNiceDropdownMaxHeight([visible]);
|
||||||
|
|
||||||
const changeMenu: DropdownProps['onOpenChange'] = (nextOpen: boolean, info) => {
|
const changeMenu: DropdownProps['onOpenChange'] = (nextOpen: boolean, info) => {
|
||||||
// 在 antd v5.8.6 版本中,点击菜单项不会触发菜单关闭,但是升级到 v5.12.2 后会触发关闭。查阅文档发现
|
|
||||||
// 在 v5.11.0 版本中增加了一个 info.source,可以通过这个来判断一下,如果是点击的是菜单项就不关闭菜单,
|
|
||||||
// 这样就可以和之前的行为保持一致了。
|
|
||||||
// 下面是模仿官方文档示例做的修改:https://ant.design/components/dropdown-cn
|
|
||||||
if (info.source === 'trigger' || nextOpen) {
|
if (info.source === 'trigger' || nextOpen) {
|
||||||
// 当鼠标快速滑过时,终止菜单的渲染,防止卡顿
|
// 当鼠标快速滑过时,终止菜单的渲染,防止卡顿
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
@ -180,13 +178,7 @@ export const SchemaSettingsDropdown: React.FC<SchemaSettingsProps> = (props) =>
|
|||||||
onOpenChange={(open, info) => {
|
onOpenChange={(open, info) => {
|
||||||
changeMenu(open, info);
|
changeMenu(open, info);
|
||||||
}}
|
}}
|
||||||
overlayClassName={css`
|
menu={{ items, style: { maxHeight: dropdownMaxHeight, overflowY: 'auto' } }}
|
||||||
.ant-dropdown-menu-item-group-list {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
menu={{ items }}
|
|
||||||
>
|
>
|
||||||
<div data-testid={props['data-testid']}>{typeof title === 'string' ? <span>{title}</span> : title}</div>
|
<div data-testid={props['data-testid']}>{typeof title === 'string' ? <span>{title}</span> : title}</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
Loading…
Reference in New Issue
Block a user