diff --git a/package-lock.json b/package-lock.json index 70e88ee5e..c280d080d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6912,6 +6912,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", diff --git a/package.json b/package.json index 6cac8d4d5..218e2b090 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "jstree": "^3.3.11", "libarchive.js": "^1.3.0", "libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv", + "lodash-es": "^4.17.21", "material-design-icons-iconfont": "^6.1.0", "native-promise-only": "^0.8.0-a", "page": "^1.11.6", diff --git a/src/components/alphaPicker/AlphaPickerComponent.js b/src/components/alphaPicker/AlphaPickerComponent.js new file mode 100644 index 000000000..717b9f969 --- /dev/null +++ b/src/components/alphaPicker/AlphaPickerComponent.js @@ -0,0 +1,40 @@ +import PropTypes from 'prop-types'; +import React, { useEffect, useRef, useState } from 'react'; + +import AlphaPicker from './alphaPicker'; + +// React compatibility wrapper component for alphaPicker.js +const AlphaPickerComponent = ({ onAlphaPicked = () => {} }) => { + const [ alphaPicker, setAlphaPicker ] = useState(null); + const element = useRef(null); + + useEffect(() => { + setAlphaPicker(new AlphaPicker({ + element: element.current, + mode: 'keyboard' + })); + + element.current?.addEventListener('alphavalueclicked', onAlphaPicked); + + return () => { + alphaPicker?.destroy(); + }; + }, []); + + useEffect(() => { + + }, [ alphaPicker ]); + + return ( +
+ ); +}; + +AlphaPickerComponent.propTypes = { + onAlphaPicked: PropTypes.func +}; + +export default AlphaPickerComponent; diff --git a/src/components/search/SearchFieldsComponent.js b/src/components/search/SearchFieldsComponent.js index 10526fa16..652e2b718 100644 --- a/src/components/search/SearchFieldsComponent.js +++ b/src/components/search/SearchFieldsComponent.js @@ -1,36 +1,85 @@ -import { Events } from 'jellyfin-apiclient'; +import debounce from 'lodash-es/debounce'; import PropTypes from 'prop-types'; -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; -import SearchFields from './searchfields'; +import AlphaPicker from '../alphaPicker/AlphaPickerComponent'; +import globalize from '../../scripts/globalize'; + +import 'material-design-icons-iconfont'; + +import '../../elements/emby-input/emby-input'; +import '../../assets/css/flexstyles.scss'; +import './searchfields.scss'; +import layoutManager from '../layoutManager'; +import browser from '../../scripts/browser'; + +// There seems to be some compatibility issues here between +// React and our legacy web components, so we need to inject +// them as an html string for now =/ +const createInputElement = () => ({ + __html: `` +}); + +const normalizeInput = (value = '') => value.trim(); const SearchFieldsComponent = ({ onSearch = () => {} }) => { - const [ searchFields, setSearchFields ] = useState(null); - const searchFieldsElement = useRef(null); + const element = useRef(null); + + const getSearchInput = () => element?.current?.querySelector('.searchfields-txtSearch'); + + const debouncedOnSearch = useMemo(() => debounce(onSearch, 400), []); useEffect(() => { - setSearchFields( - new SearchFields({ element: searchFieldsElement.current }) - ); + getSearchInput()?.addEventListener('input', e => { + debouncedOnSearch(normalizeInput(e.target?.value)); + }); + getSearchInput()?.focus(); return () => { - searchFields?.destroy(); + debouncedOnSearch.cancel(); }; }, []); - useEffect(() => { - if (searchFields) { - Events.on(searchFields, 'search', (e, value) => { - onSearch(value); - }); + const onAlphaPicked = e => { + const value = e.detail.value; + const searchInput = getSearchInput(); + + if (value === 'backspace') { + const currentValue = searchInput.value; + searchInput.value = currentValue.length ? currentValue.substring(0, currentValue.length - 1) : ''; + } else { + searchInput.value += value; } - }, [ searchFields ]); + + searchInput.dispatchEvent(new CustomEvent('input', { bubbles: true })); + }; return ( + ref={element} + > +