mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
ui: special behavior of UserSelectAutoComplete when multi (#286)
This commit is contained in:
1 parent
f384ae70fb
commit
538862de07
4 files changed
+89
-15
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
import { assign } from 'lodash';
|
||||
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
||||
import AutoComplete from '.';
|
||||
@@ -13,19 +14,37 @@ export default class UserSelectAutoComplete extends AutoComplete {
|
||||
classes: 'user-select',
|
||||
...options,
|
||||
});
|
||||
this.client = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
refetchOnReconnect: false,
|
||||
retry: false,
|
||||
staleTime: Infinity,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
value() {
|
||||
if (this.options.multi) return this.ref?.getSelectedItems().map((item) => item._id) ?? this.$dom.val();
|
||||
return this.ref?.getSelectedItems()[0] ?? null;
|
||||
}
|
||||
|
||||
attach() {
|
||||
const value = this.$dom.val();
|
||||
ReactDOM.render(
|
||||
<UserSelectAutoCompleteFC
|
||||
ref={(ref) => { this.ref = ref; }}
|
||||
height="34px"
|
||||
defaultItems={value}
|
||||
onChange={this.onChange}
|
||||
multi={this.options.multi}
|
||||
freeSolo={this.options.multi}
|
||||
/>,
|
||||
<QueryClientProvider client={this.client}>
|
||||
<UserSelectAutoCompleteFC
|
||||
ref={(ref) => { this.ref = ref; }}
|
||||
height="34px"
|
||||
defaultItems={value}
|
||||
onChange={this.onChange}
|
||||
multi={this.options.multi}
|
||||
freeSolo={this.options.multi}
|
||||
/>
|
||||
</QueryClientProvider>,
|
||||
this.container,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
|
||||
// if you need fix height, set to at least "30px"
|
||||
// for Hydro, no less then "34px" can be better
|
||||
const height = props.height ?? 'auto';
|
||||
const disabled = props.disabled ?? false;
|
||||
const disabledHint = props.disabledHint ?? '';
|
||||
const listStyle = props.listStyle ?? {};
|
||||
const itemsFn = props.itemsFn ?? (async () => []);
|
||||
const renderItem = props.renderItem ?? ((item) => item);
|
||||
@@ -22,7 +24,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
|
||||
const multi = props.multi ?? false;
|
||||
const rawDefaultItems = props.defaultItems ?? [];
|
||||
const defaultItems = typeof rawDefaultItems === 'string'
|
||||
? props.defaultItems.split(',').map((i) => i.trim()).filter((i) => i.length > 0) : rawDefaultItems;
|
||||
? rawDefaultItems.split(',').map((i) => i.trim()).filter((i) => i.length > 0) : rawDefaultItems;
|
||||
const allowEmptyQuery = props.allowEmptyQuery ?? false;
|
||||
const freeSolo = props.freeSolo ?? false;
|
||||
const freeSoloConverter = freeSolo ? props.freeSoloConverter ?? ((i) => i) : ((i) => i);
|
||||
@@ -188,7 +190,7 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
|
||||
setFocused(true);
|
||||
inputRef.current?.focus();
|
||||
},
|
||||
}));
|
||||
}), [selected, selectedKeys, inputRef, multi]);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'inline-block', width: '100%' }}>
|
||||
@@ -202,9 +204,17 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
|
||||
<Icon name="close" onClick={() => toggleItem(item)} />
|
||||
</div>
|
||||
))}
|
||||
{disabled && (
|
||||
<input
|
||||
disabled
|
||||
autoComplete="off"
|
||||
value={disabledHint}
|
||||
/>
|
||||
)}
|
||||
<input
|
||||
ref={inputRef}
|
||||
autoComplete="off"
|
||||
hidden={disabled}
|
||||
onChange={(e) => {
|
||||
dispatchChange();
|
||||
handleInputChange(e);
|
||||
@@ -243,6 +253,8 @@ const AutoComplete = forwardRef(function AutoComplete(props, ref) {
|
||||
AutoComplete.propTypes = {
|
||||
width: PropTypes.string,
|
||||
height: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
disabledHint: PropTypes.string,
|
||||
listStyle: PropTypes.object,
|
||||
itemsFn: PropTypes.func.isRequired,
|
||||
itemKey: PropTypes.func,
|
||||
@@ -259,6 +271,8 @@ AutoComplete.propTypes = {
|
||||
AutoComplete.defaultProps = {
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
disabled: false,
|
||||
disabledHint: '',
|
||||
listStyle: {},
|
||||
renderItem: (item) => item,
|
||||
itemText: (item) => item,
|
||||
|
||||
@@ -1,10 +1,44 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import React, {
|
||||
forwardRef, createRef, useImperativeHandle, useRef, useEffect,
|
||||
} from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import PropTypes from 'prop-types';
|
||||
import api, { gql } from 'vj/utils/api';
|
||||
import AutoComplete from './AutoComplete';
|
||||
|
||||
// eslint-disable-next-line prefer-arrow-callback
|
||||
const UserSelectAutoComplete = forwardRef(function UserSelectAutoComplete(props, ref) {
|
||||
const multi = props.multi ?? false;
|
||||
const rawDefaultItems = props.defaultItems ?? '';
|
||||
const defaultItems = multi ? rawDefaultItems
|
||||
.split(',')
|
||||
.map((i) => i.trim())
|
||||
.filter((i) => i.length > 0)
|
||||
.map((i) => +i) : rawDefaultItems;
|
||||
|
||||
const comRef = createRef();
|
||||
const itemsBox = useRef([]);
|
||||
const { isLoading } = useQuery(['default_user', defaultItems], async () => {
|
||||
if (!multi || defaultItems.length === 0) return;
|
||||
const items = await api(gql`
|
||||
users(ids: ${defaultItems}) {
|
||||
_id
|
||||
uname
|
||||
}
|
||||
`, ['data', 'users']);
|
||||
itemsBox.current = items;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (multi && defaultItems.length > 0) {
|
||||
comRef.current.setSelectedItems(itemsBox.current);
|
||||
}
|
||||
}, [itemsBox.current]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
...comRef.current,
|
||||
}));
|
||||
|
||||
const itemsFn = (query) => api(gql`
|
||||
users(search: ${query}) {
|
||||
_id
|
||||
@@ -15,6 +49,8 @@ const UserSelectAutoComplete = forwardRef(function UserSelectAutoComplete(props,
|
||||
|
||||
const itemText = (user) => user.uname || user;
|
||||
|
||||
const itemKey = (user) => user._id;
|
||||
|
||||
const renderItem = (user) => (
|
||||
<div className="media">
|
||||
<div className="media__left medium">
|
||||
@@ -29,11 +65,15 @@ const UserSelectAutoComplete = forwardRef(function UserSelectAutoComplete(props,
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
ref={ref}
|
||||
ref={comRef}
|
||||
{...props}
|
||||
disabled={isLoading}
|
||||
disabledHint="Loading..."
|
||||
itemsFn={itemsFn}
|
||||
itemText={itemText}
|
||||
itemKey={multi ? itemKey : itemText}
|
||||
renderItem={renderItem}
|
||||
{...props}
|
||||
defaultItems={multi ? [] : rawDefaultItems}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -44,7 +84,7 @@ UserSelectAutoComplete.propTypes = {
|
||||
listStyle: PropTypes.object,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
multi: PropTypes.bool,
|
||||
defaultItems: PropTypes.oneOfType([(PropTypes.arrayOf(PropTypes.any)), PropTypes.string]),
|
||||
defaultItems: PropTypes.string,
|
||||
allowEmptyQuery: PropTypes.bool,
|
||||
freeSolo: PropTypes.bool,
|
||||
freeSoloConverter: PropTypes.func,
|
||||
@@ -55,7 +95,7 @@ UserSelectAutoComplete.defaultProps = {
|
||||
height: 'auto',
|
||||
listStyle: {},
|
||||
multi: false,
|
||||
defaultItems: [],
|
||||
defaultItems: '',
|
||||
allowEmptyQuery: false,
|
||||
freeSolo: false,
|
||||
freeSoloConverter: (input) => input,
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"markdown-it-table-of-contents": "^0.6.0",
|
||||
"mongodb": "^3.7.3",
|
||||
"nunjucks": "^3.2.3",
|
||||
"react-query": "^3.34.7",
|
||||
"streamsaver": "^2.0.5",
|
||||
"xss": "^1.0.10"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user