Skip to content

Commit

Permalink
Merge da30645 into 8a0c321
Browse files Browse the repository at this point in the history
  • Loading branch information
pointhalo committed Sep 18, 2024
2 parents 8a0c321 + da30645 commit 2f31c14
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 80 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
],
"cSpell.words": [
"backtop",
"douyinfe",
"Splited"
]
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "semi",
"version": "0.0.1",
"description": "Semi monorepo main project",
"author": "",
"author": "DouyinFe",
"workspaces": [
"packages/**"
],
Expand Down Expand Up @@ -60,6 +60,7 @@
"@visactor/vchart-semi-theme": "^1.10.4",
"aos": "^2.3.4",
"camelcase": "^6.2.0",
"chalk": "^5.3.0",
"chroma-js": "^2.1.2",
"classnames": "^2.3.1",
"copy-text-to-clipboard": "^2.2.0",
Expand Down Expand Up @@ -138,6 +139,7 @@
"@storybook/cli": "^7.0.7",
"@storybook/react": "^7.0.7",
"@svgr/webpack": "^5.5.0",
"@testing-library/react": "^12",
"@types/classnames": "^2.3.0",
"@types/enhanced-resolve": "^3.0.7",
"@types/fs-extra": "^9.0.12",
Expand All @@ -153,7 +155,6 @@
"@types/webpack": "^4.41.30",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"awesome-typescript-loader": "^5.2.1",
"axios": "^0.21.1",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^24.9.0",
Expand All @@ -170,7 +171,6 @@
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"enzyme-to-json": "^3.6.2",
"@testing-library/react": "^12",
"esbuild": "^0.14.47",
"esbuild-loader": "^2.14.0",
"eslint": "^7.32.0",
Expand Down Expand Up @@ -215,7 +215,7 @@
"ts-loader": "^5.4.5",
"typescript": "^4.8.3",
"webpack": "^5.77.0",
"webpack-cli": "^3.3.12",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^3.11.2",
"webpackbar": "^5.0.0-3"
},
Expand Down
5 changes: 2 additions & 3 deletions packages/semi-foundation/autoComplete/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { BASE_CLASS_PREFIX, VALIDATE_STATUS } from '../base/constants';

const cssClasses = {
PREFIX: `${BASE_CLASS_PREFIX}-autocomplete`,
PREFIX_OPTION: `${BASE_CLASS_PREFIX}-autoComplete-option`,
PREFIX_GROUP: `${BASE_CLASS_PREFIX}-autoComplete-group`,

PREFIX_OPTION: `${BASE_CLASS_PREFIX}-autocomplete-option`,
PREFIX_GROUP: `${BASE_CLASS_PREFIX}-autocomplete-group`,
};

const strings = {
Expand Down
2 changes: 2 additions & 0 deletions packages/semi-foundation/autoComplete/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface AutoCompleteAdapter<P = Record<string, any>, S = Record<string,
updateInputValue: (inputValue: string | number) => void;
toggleListVisible: (isShow: boolean) => void;
updateOptionList: (optionList: Array<StateOptionItem>) => void;
updateScrollTop: (index: number) => void;
updateSelection: (selection: Map<any, any>) => void;
notifySearch: (inputValue: string) => void;
notifyChange: (value: string | number) => void;
Expand Down Expand Up @@ -387,6 +388,7 @@ class AutoCompleteFoundation<P = Record<string, any>, S = Record<string, any>> e
index = nearestActiveOption;
}
this._adapter.updateFocusIndex(index);
this._adapter.updateScrollTop(index);
}

_handleArrowKeyDown(offset: number): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/semi-foundation/autoComplete/option.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$module: #{$prefix}-autoComplete;
$module: #{$prefix}-autocomplete;
$filterable: #{$module}-filterable;

.#{$module}-option {
Expand Down
12 changes: 6 additions & 6 deletions packages/semi-ui/autoComplete/__test__/autoComplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe('AutoComplete', () => {
};
let ac = getAc(props);
expect(ac.exists(`.${BASE_CLASS_PREFIX}-autocomplete-loading-wrapper`)).toEqual(true);
expect(ac.exists(`.${BASE_CLASS_PREFIX}-autoComplete-option`)).toEqual(false);
expect(ac.exists(`.${BASE_CLASS_PREFIX}-autocomplete-option`)).toEqual(false);
});

it('【onSelect】trigger onSelect when click candidate option', () => {
Expand All @@ -204,7 +204,7 @@ describe('AutoComplete', () => {
...commonProps,
};
let ac = getAc(props);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autoComplete-option`);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autocomplete-option`);
let firstOption = options.at(0);
const nativeEvent = { nativeEvent: { stopImmediatePropagation: noop } };
firstOption.simulate('click', nativeEvent);
Expand All @@ -223,7 +223,7 @@ describe('AutoComplete', () => {
...commonProps,
};
let ac = getAc(props);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autoComplete-option`);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autocomplete-option`);
let firstOption = options.at(0);
const nativeEvent = { nativeEvent: { stopImmediatePropagation: noop } };
firstOption.simulate('click', nativeEvent);
Expand Down Expand Up @@ -269,7 +269,7 @@ describe('AutoComplete', () => {
renderSelectedItem: option => option.email,
};
let ac = getAc(props);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autoComplete-option`);
let options = ac.find(`.${BASE_CLASS_PREFIX}-autocomplete-option`);
let firstOption = options.at(0);
const nativeEvent = { nativeEvent: { stopImmediatePropagation: noop } };
firstOption.simulate('click', nativeEvent);
Expand Down Expand Up @@ -306,7 +306,7 @@ describe('AutoComplete', () => {
value: '',
};
const ac = getAc(props);
ac.find(`.${BASE_CLASS_PREFIX}-autoComplete-option`)
ac.find(`.${BASE_CLASS_PREFIX}-autocomplete-option`)
.at(0)
.simulate('click');
expect(fakeOnChange.calledWith('XK')).toEqual(true);
Expand Down Expand Up @@ -374,7 +374,7 @@ describe('AutoComplete', () => {
let event = { target: { value: 'abc' } };
component.find('input').simulate('change', event);
expect(spyOnChange.calledWith('abc')).toEqual(true);
let options = component.find(`.${BASE_CLASS_PREFIX}-autoComplete-option`);
let options = component.find(`.${BASE_CLASS_PREFIX}-autocomplete-option`);
let firstOption = options.at(0);
const nativeEvent = { nativeEvent: { stopImmediatePropagation: noop } };
firstOption.simulate('click', nativeEvent);
Expand Down
46 changes: 45 additions & 1 deletion packages/semi-ui/autoComplete/_story/autoComplete.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component, useState } from 'react';

import CustomTrigger from './CustomTrigger';
import AutoComplete from '../index';
import { Form } from '../../index';
import { Form, Avatar } from '../../index';
import { IconSearch } from '@douyinfe/semi-icons';

export default {
Expand Down Expand Up @@ -371,3 +371,47 @@ export const ControlledOnSelectWithObjectDemo = () => {
</Form>
);
};


export const AutoScrollToKeyboardUpDown = () => {

const [data, setData] = useState([]);
const getData = (v) => {
let newData = Array.from({ length: 20 }, (v, i) => ({ label: `option-${i}`, value: i, 'data-cy': `option-${i}` }));
setData(newData);
};

const renderOption = (item) => {
let optionStyle = {
display: 'flex',
};
return (
<>
<Avatar color={'cyan'} size="small">
Semi
</Avatar>
<div style={{ marginLeft: 4 }}>
<div style={{ fontSize: 14, marginLeft: 4 }}>{item.label}</div>
<div style={{ marginLeft: 4 }}>{item.value}</div>
</div>
</>
);
}

return <>
<AutoComplete
data={data}
onSearch={(v) => getData(v)}
style={{ width: 320 }}
>
</AutoComplete>
<AutoComplete
placeholder='with render'
data={data}
renderItem={renderOption}
onSearch={(v) => getData(v)}
style={{ width: 320 }}
>
</AutoComplete>
</>
}
36 changes: 34 additions & 2 deletions packages/semi-ui/autoComplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isEqual, noop } from 'lodash';
import { strings, cssClasses } from '@douyinfe/semi-foundation/autoComplete/constants';
import AutoCompleteFoundation, { AutoCompleteAdapter, StateOptionItem, DataItem } from '@douyinfe/semi-foundation/autoComplete/foundation';
import { numbers as popoverNumbers } from '@douyinfe/semi-foundation/popover/constants';
import getDataAttr from '@douyinfe/semi-foundation/utils/getDataAttr';
import { getUuidShort } from '@douyinfe/semi-foundation/utils/uuid';
import BaseComponent, { ValidateStatus } from '../_base/baseComponent';
import { Position } from '../tooltip';
import Spin from '../spin';
Expand Down Expand Up @@ -199,6 +199,7 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple

triggerRef: React.RefObject<HTMLDivElement> | null;
optionsRef: React.RefObject<HTMLDivElement> | null;
optionListId: string;

private clickOutsideHandler: (e: Event) => void | null;

Expand All @@ -222,6 +223,7 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple
this.triggerRef = React.createRef();
this.optionsRef = React.createRef();
this.clickOutsideHandler = null;
this.optionListId = '';

warning(
'triggerRender' in this.props && typeof this.props.triggerRender === 'function',
Expand All @@ -247,6 +249,30 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple
updateFocusIndex: (focusIndex: number): void => {
this.setState({ focusIndex });
},
updateScrollTop: (index?: number) => {
let optionClassName;
/**
* Unlike Select which needs to process renderOptionItem separately, when renderItem is enabled in autocomplete
* the content passed by the user is still wrapped in the selector of .semi-autocomplete-option
* so the selector does not need to be judged separately.
*/
optionClassName = `.${prefixCls}-option-selected`;
if (index !== undefined) {
optionClassName = `.${prefixCls}-option:nth-child(${index + 1})`;
}

let destNode = document.querySelector(`#${prefixCls}-${this.optionListId} ${optionClassName}`) as HTMLDivElement;
if (Array.isArray(destNode)) {
destNode = destNode[0];
}
if (destNode) {
const destParent = destNode.parentNode as HTMLDivElement;
destParent.scrollTop = destNode.offsetTop -
destParent.offsetTop -
(destParent.clientHeight / 2) +
(destNode.clientHeight / 2);
}
},
};
return {
...super.adapter,
Expand Down Expand Up @@ -329,6 +355,7 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple

componentDidMount() {
this.foundation.init();
this.optionListId = getUuidShort();
}

componentWillUnmount() {
Expand Down Expand Up @@ -497,7 +524,12 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple
...dropdownStyle,
};
return (
<div className={listCls} role="listbox" style={style}>
<div
className={listCls}
role="listbox"
style={style}
id={`${prefixCls}-${this.optionListId}`}
>
{!loading ? optionsNode : this.renderLoading()}
</div>
);
Expand Down
Loading

0 comments on commit 2f31c14

Please sign in to comment.