Skip to content

Commit

Permalink
feat(cascader): support auto scroll to first selected element (#3357)
Browse files Browse the repository at this point in the history
  • Loading branch information
uyarn authored Feb 5, 2025
1 parent f259082 commit 34272fa
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 4 deletions.
27 changes: 26 additions & 1 deletion src/cascader/Cascader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { pick , omit } from 'lodash-es';
import { pick, omit } from 'lodash-es';
import Panel from './components/Panel';
import SelectInput from '../select-input';
import FakeArrow from '../common/FakeArrow';
Expand Down Expand Up @@ -91,6 +91,30 @@ const Cascader: React.FC<CascaderProps> = (originalProps) => {
const renderValueDisplay = () => parseContentTNode(props.valueDisplay, valueDisplayParams);

const { setVisible, visible, inputVal, setInputVal } = cascaderContext;

const updateScrollTop = (content: HTMLDivElement) => {
const cascaderMenuList = content.querySelectorAll(`.${COMPONENT_NAME}__menu`);
requestAnimationFrame(() => {
cascaderMenuList.forEach((menu: HTMLDivElement) => {
const firstSelectedNode: HTMLDivElement =
menu?.querySelector(`.${classPrefix}-is-selected`) || menu?.querySelector(`.${classPrefix}-is-expanded`);
if (!firstSelectedNode || !menu) return;

const { paddingBottom } = getComputedStyle(firstSelectedNode);
const { marginBottom } = getComputedStyle(menu);
const elementBottomHeight = parseInt(paddingBottom, 10) + parseInt(marginBottom, 10);

const updateValue =
firstSelectedNode.offsetTop -
menu.offsetTop -
(menu.clientHeight - firstSelectedNode.clientHeight) +
elementBottomHeight;
// eslint-disable-next-line no-param-reassign
menu.scrollTop = updateValue;
});
});
};

return (
<SelectInput
className={classNames(COMPONENT_NAME, props.className)}
Expand All @@ -114,6 +138,7 @@ const Cascader: React.FC<CascaderProps> = (originalProps) => {
valueDisplay={renderValueDisplay()}
suffix={props.suffix}
suffixIcon={renderSuffixIcon()}
updateScrollTop={updateScrollTop}
popupProps={{
...props.popupProps,
overlayInnerStyle: panels.length && !props.loading ? { width: 'auto' } : {},
Expand Down
86 changes: 85 additions & 1 deletion src/cascader/_example/multiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Cascader } from 'tdesign-react';
import type { CascaderProps, CascaderValue } from 'tdesign-react';

export default function Example() {
const [value, setValue] = useState<CascaderValue>(['1.1']);
const [value, setValue] = useState<CascaderValue>(['8.1']);
const options = [
{
label: '选项一',
Expand Down Expand Up @@ -37,6 +37,90 @@ export default function Example() {
},
],
},
{
label: '选项三',
value: '3',
children: [
{
label: '子选项一',
value: '3.1',
},
{
label: '子选项二',
value: '3.2',
},
],
},
{
label: '选项四',
value: '4',
children: [
{
label: '子选项一',
value: '4.1',
},
{
label: '子选项二',
value: '4.2',
},
],
},
{
label: '选项五',
value: '5',
children: [
{
label: '子选项一',
value: '5.1',
},
{
label: '子选项二',
value: '5.2',
},
],
},
{
label: '选项六',
value: '6',
children: [
{
label: '子选项一',
value: '6.1',
},
{
label: '子选项二',
value: '6.2',
},
],
},
{
label: '选项七',
value: '7',
children: [
{
label: '子选项一',
value: '7.1',
},
{
label: '子选项二',
value: '7.2',
},
],
},
{
label: '选项8',
value: '8',
children: [
{
label: '子选项一',
value: '8.1',
},
{
label: '子选项二',
value: '8.2',
},
],
},
];

const onChange: CascaderProps['onChange'] = (value) => {
Expand Down
4 changes: 2 additions & 2 deletions test/snap/__snapshots__/csr.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19620,9 +19620,9 @@ exports[`csr snapshot test > csr test src/cascader/_example/multiple.tsx 1`] = `
class="t-tag t-tag--default t-tag--dark"
>
<span
title="选项一/子选项一"
title="选项8/子选项一"
>
选项一/子选项一
选项8/子选项一
</span>
<svg
class="t-icon t-icon-close t-tag__icon-close"
Expand Down

0 comments on commit 34272fa

Please sign in to comment.