diff --git a/packages/ui-default/components/autocomplete/components/AutoComplete.tsx b/packages/ui-default/components/autocomplete/components/AutoComplete.tsx index 6da9e5a0..a3357fea 100644 --- a/packages/ui-default/components/autocomplete/components/AutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/components/AutoComplete.tsx @@ -38,6 +38,7 @@ export interface AutoCompleteHandle { setSelectedItems: (items: Item[]) => void; getQuery: () => string; setQuery: (query: string) => void; + setSelectedKeys: (keys: string[]) => void; triggerQuery: () => any; closeList: () => void; /** returns comma seperated value text */ @@ -69,7 +70,7 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re const [focused, setFocused] = useState(false); // is focused const [selected, setSelected] = useState([]); // selected items - const [selectedKeys, setSelectedKeys] = useState(props.selectedKeys); // keys of selected items + const [selectedKeys, setSelectedKeys] = useState(props.selectedKeys || []); // keys of selected items const [itemList, setItemList] = useState([]); // items list const [currentItem, setCurrentItem] = useState(null); // index of current item (in item list) const [rerender, setRerender] = useState(false); @@ -81,16 +82,6 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re const queryCache = props.cacheKey ? superCache[props.cacheKey].query : useRef({}).current; const valueCache = props.cacheKey ? superCache[props.cacheKey].value : useRef({}).current; - useEffect(() => { - const ids = []; - for (const key of selectedKeys) if (!valueCache[key]) ids.push(key); - if (!ids.length) return; - Promise.resolve(props.fetchItems(ids)).then((items) => { - for (const item of items) valueCache[itemKey(item)] = item; - setRerender(!rerender); - }); - }, [selectedKeys]); - const queryList = async (query) => { if (!query && !allowEmptyQuery) { setItemList([]); @@ -104,22 +95,25 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re }; const dispatchChange = () => { - const query = inputRef.current?.value; - const val = [...selectedKeys, query].filter((i) => i).join(','); - onChange(val); + if (!multi) onChange(inputRef.current?.value); + else onChange(selectedKeys.join(',')); }; useEffect(() => { dispatchChange(); + const ids = []; + for (const key of selectedKeys) if (!valueCache[key]) ids.push(key); + if (!ids.length) return; + Promise.resolve(props.fetchItems(ids)).then((items) => { + for (const item of items) valueCache[itemKey(item)] = item; + setRerender(!rerender); + }); }, [selectedKeys, multi]); - const handleInputChange = debounce(async (e) => { - const { target } = e; - const { value } = target; - queryList(value); - }, 300); + const handleInputChange = debounce((e?) => queryList(e ? e.target.value : ''), 300); const toggleItem = (item: T, key = itemKey(item)) => { + const shouldKeepOpen = allowEmptyQuery && inputRef.current.value === '' && !multi; if (multi) { const idx = selectedKeys.indexOf(key); if (idx !== -1) { @@ -145,8 +139,10 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re inputRef.current.value = key; dispatchChange(); } - setItemList([]); - setCurrentItem(null); + if (!shouldKeepOpen) { + setItemList([]); + setCurrentItem(null); + } }; const handleInputKeyDown = (e) => { @@ -169,7 +165,7 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re } if (key === 'Backspace') { if (target.value.length > 0) return; - if (selected.length > 0) { + if (selectedKeys.length > 0) { setSelected((s) => s.slice(0, -1)); setSelectedKeys((s) => s.slice(0, -1)); } @@ -209,6 +205,7 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re setQuery: (query) => { if (inputRef.current) inputRef.current.value = query; }, + setSelectedKeys: (keys) => setSelectedKeys(keys), triggerQuery: () => queryList(inputRef.current?.value), closeList: () => { setItemList([]); @@ -257,7 +254,10 @@ const AutoComplete = forwardRef(function Impl(props: AutoCompleteProps, re dispatchChange(); handleInputChange(e); }} - onFocus={() => setFocused(true)} + onFocus={() => { + if (allowEmptyQuery) handleInputChange(); + setFocused(true); + }} onBlur={() => setFocused(false)} onKeyDown={handleInputKeyDown} defaultValue={multi ? '' : selectedKeys.join(',')} diff --git a/packages/ui-default/components/autocomplete/components/CustomSelectAutoComplete.tsx b/packages/ui-default/components/autocomplete/components/CustomSelectAutoComplete.tsx index 1a922049..70d185a0 100644 --- a/packages/ui-default/components/autocomplete/components/CustomSelectAutoComplete.tsx +++ b/packages/ui-default/components/autocomplete/components/CustomSelectAutoComplete.tsx @@ -2,13 +2,23 @@ import React from 'react'; import PropTypes from 'prop-types'; import AutoComplete from './AutoComplete'; +type DefaultProps = { + _id: string; + name: string; +} & string; + const CustomSelectAutoComplete = React.forwardRef((props, ref) => ( - + ref={ref as any} - queryItems={(query) => props.data.filter((i) => (i.name ? i.name.match(query) : i.match(query)))} + fetchItems={(keys) => props.data.filter((i) => (i._id ? keys.includes(i._id) : keys.includes(i)))} + queryItems={(query) => props.data.filter((i) => (i.name + ? i.name.toLowerCase().match(query.toLowerCase()) + : i.toString().toLowerCase().match(query.toLowerCase()) + ))} itemText={(item) => `${item.name || item}`} itemKey={(item) => `${item._id?.toString() || item.name || item}`} renderItem={(item) => `${item.name || item}`} + allowEmptyQuery {...props} /> )); @@ -34,7 +44,6 @@ CustomSelectAutoComplete.defaultProps = { listStyle: {}, multi: false, selectedKeys: [], - allowEmptyQuery: false, freeSolo: false, freeSoloConverter: (input) => input, }; diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 04aac7fa..0e541919 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.34.33", + "version": "4.34.34", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/types.ts b/packages/ui-default/types.ts index db9dfd50..da16dcc3 100644 --- a/packages/ui-default/types.ts +++ b/packages/ui-default/types.ts @@ -4,3 +4,4 @@ declare let UiContext: any; declare let Hydro: any; // eslint-disable-next-line camelcase declare let node_modules: any; +declare let LANGS: Record;