Skip to content

Commit

Permalink
Mentions data driven (ant-design#38630)
Browse files Browse the repository at this point in the history
* feat: reset and force update

* feat: update package

* feat: reset

* feat: update for viewer

* feat: update for viewer

* feat: update for viewer

* feat: update for viewer

* feat: update for viewer

* update doc

* feat: add waring

* feat: update doc

* feat: add test case
  • Loading branch information
heiyu4585 committed Nov 22, 2022
1 parent 4288039 commit 107ec18
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 28 deletions.
19 changes: 18 additions & 1 deletion components/mentions/__tests__/index.test.tsx
@@ -1,5 +1,5 @@
import React from 'react';
import Mentions from '..';
import Mentions,{Option} from '..';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
Expand Down Expand Up @@ -84,4 +84,21 @@ describe('Mentions', () => {
expect(wrapper.container.querySelectorAll('li.ant-mentions-dropdown-menu-item').length).toBe(1);
expect(wrapper.container.querySelectorAll('.bamboo-light').length).toBeTruthy();
});

it('warning if use Mentions.Option', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(
<Mentions
style={{ width: '100%' }}
defaultValue="@afc163"
>
<Option value="afc163">afc163</Option>
<Option value="zombieJ">zombieJ</Option>
<Option value="yesmeck">yesmeck</Option>
</Mentions>,
);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Mentions] `Mentions.Option` is deprecated. Please use `options` instead.',
);
});
});
57 changes: 57 additions & 0 deletions components/mentions/demo/async.tsx
@@ -0,0 +1,57 @@
import React, { useCallback, useRef, useState } from 'react';
import { Mentions } from 'antd';
import debounce from 'lodash/debounce';

const App: React.FC = () => {
const [loading, setLoading] = useState(false);
const [users, setUsers] = useState<{ login: string; avatar_url: string }[]>([]);
const ref = useRef<string>();

const loadGithubUsers = (key: string) => {
if (!key) {
setUsers([]);
return;
}

fetch(`https://api.github.com/search/users?q=${key}`)
.then((res) => res.json())
.then(({ options = [] }) => {
if (ref.current !== key) return;

setLoading(false);
setUsers(options.slice(0, 10));
});
};

const debounceLoadGithubUsers = useCallback(debounce(loadGithubUsers, 800), []);

const onSearch = (search: string) => {
console.log('Search:', search);
ref.current = search;
setLoading(!!search);
setUsers([]);

debounceLoadGithubUsers(search);
};

return (
<Mentions
style={{ width: '100%' }}
loading={loading}
onSearch={onSearch}
options={users.map(({ login, avatar_url: avatar }) => ({
key: login,
value: login,
className: 'antd-demo-dynamic-option',
label: (
<>
<img src={avatar} alt={login} />
<span>{login}</span>
</>
),
}))}
/>
);
};

export default App;
25 changes: 25 additions & 0 deletions components/mentions/demo/autoSize.tsx
@@ -0,0 +1,25 @@
import React from 'react';
import { Mentions } from 'antd';

const App: React.FC = () => (
<Mentions
autoSize
style={{ width: '100%' }}
options={[
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
{
value: 'yesmeck',
label: 'yesmeck',
},
]}
/>
);

export default App;
36 changes: 36 additions & 0 deletions components/mentions/demo/basic.tsx
@@ -0,0 +1,36 @@
import React from 'react';
import { Mentions } from 'antd';
import type { MentionsOptionProps } from 'antd/es/mentions';

const onChange = (value: string) => {
console.log('Change:', value);
};

const onSelect = (option: MentionsOptionProps) => {
console.log('select', option);
};

const App: React.FC = () => (
<Mentions
style={{ width: '100%' }}
onChange={onChange}
onSelect={onSelect}
defaultValue="@afc163"
options={[
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
{
value: 'yesmeck',
label: 'yesmeck',
},
]}
/>
);

export default App;
96 changes: 96 additions & 0 deletions components/mentions/demo/form.tsx
@@ -0,0 +1,96 @@
import React from 'react';
import { Button, Form, Mentions } from 'antd';

const { getMentions } = Mentions;

const App: React.FC = () => {
const [form] = Form.useForm();

const onReset = () => {
form.resetFields();
};

const onFinish = async () => {
try {
const values = await form.validateFields();
console.log('Submit:', values);
} catch (errInfo) {
console.log('Error:', errInfo);
}
};

const checkMention = async (_: any, value: string) => {
const mentions = getMentions(value);

if (mentions.length < 2) {
throw new Error('More than one must be selected!');
}
};

return (
<Form form={form} layout="horizontal" onFinish={onFinish}>
<Form.Item
name="coders"
label="Top coders"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
rules={[{ validator: checkMention }]}
>
<Mentions
rows={1}
options={[
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
{
value: 'yesmeck',
label: 'yesmeck',
},
]}
/>
</Form.Item>
<Form.Item
name="bio"
label="Bio"
labelCol={{ span: 6 }}
wrapperCol={{ span: 16 }}
rules={[{ required: true }]}
>
<Mentions
rows={3}
placeholder="You can use @ to ref user here"
options={[
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
{
value: 'yesmeck',
label: 'yesmeck',
},
]}
/>
</Form.Item>
<Form.Item wrapperCol={{ span: 14, offset: 6 }}>
<Button htmlType="submit" type="primary">
Submit
</Button>
&nbsp;&nbsp;&nbsp;
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
</Form.Item>
</Form>
);
};

export default App;
25 changes: 25 additions & 0 deletions components/mentions/demo/placement.tsx
@@ -0,0 +1,25 @@
import React from 'react';
import { Mentions } from 'antd';

const App: React.FC = () => (
<Mentions
style={{ width: '100%' }}
placement="top"
options={[
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
{
value: 'yesmeck',
label: 'yesmeck',
},
]}
/>
);

export default App;
33 changes: 33 additions & 0 deletions components/mentions/demo/prefix.tsx
@@ -0,0 +1,33 @@
import React, { useState } from 'react';
import { Mentions } from 'antd';

const MOCK_DATA = {
'@': ['afc163', 'zombiej', 'yesmeck'],
'#': ['1.0', '2.0', '3.0'],
};

type PrefixType = keyof typeof MOCK_DATA;

const App: React.FC = () => {
const [prefix, setPrefix] = useState<PrefixType>('@');

const onSearch = (_: string, newPrefix: PrefixType) => {
setPrefix(newPrefix);
};

return (
<Mentions
style={{ width: '100%' }}
placeholder="input @ to mention people, # to mention tag"
prefix={['@', '#']}
onSearch={onSearch}
options={(MOCK_DATA[prefix] || []).map((value) => ({
key: value,
value,
label: value,
}))}
/>
);
};

export default App;
29 changes: 29 additions & 0 deletions components/mentions/demo/readonly.tsx
@@ -0,0 +1,29 @@
import React from 'react';
import { Mentions } from 'antd';

const options = ['afc163', 'zombiej', 'yesmeck'].map((value) => ({
value,
key: value,
label: value,
}));

const App: React.FC = () => (
<>
<div style={{ marginBottom: 10 }}>
<Mentions
style={{ width: '100%' }}
placeholder="this is disabled Mentions"
disabled
options={options}
/>
</div>
<Mentions
style={{ width: '100%' }}
placeholder="this is readOnly Mentions"
readOnly
options={options}
/>
</>
);

export default App;
21 changes: 21 additions & 0 deletions components/mentions/demo/render-panel.tsx
@@ -0,0 +1,21 @@
import React from 'react';
import { Mentions } from 'antd';

const { _InternalPanelDoNotUseOrYouWillBeFired: InternalMentions } = Mentions;

const options = [
{
value: 'afc163',
label: 'afc163',
},
{
value: 'zombieJ',
label: 'zombieJ',
},
]

const App: React.FC = () => (
<InternalMentions style={{ width: '100%' }} value="@" options={options}/>
);

export default App;

0 comments on commit 107ec18

Please sign in to comment.