diff --git a/packages/desktop-client/src/components/accounts/Filters.js b/packages/desktop-client/src/components/accounts/Filters.js index 5a75914e2a5621eddead8f88ae79b61717f98e30..1fccb82a27e8bf1a0ce3c1f354235a34b6ee65b4 100644 --- a/packages/desktop-client/src/components/accounts/Filters.js +++ b/packages/desktop-client/src/components/accounts/Filters.js @@ -166,7 +166,7 @@ function ConfigureField({ width={300} onClose={() => dispatch({ type: 'close' })} > - <FocusScope contain> + <FocusScope> <View style={{ marginBottom: 10 }}> {field === 'amount' || field === 'date' ? ( <CustomSelect diff --git a/packages/desktop-client/src/components/accounts/TransactionsTable.js b/packages/desktop-client/src/components/accounts/TransactionsTable.js index 83dbe1c1a5720f19351b4b7428ef2b8fccb43e16..5b6dfd579c07394d8356f0e77708a166fd43251f 100644 --- a/packages/desktop-client/src/components/accounts/TransactionsTable.js +++ b/packages/desktop-client/src/components/accounts/TransactionsTable.js @@ -40,7 +40,8 @@ import AccountAutocomplete from 'loot-design/src/components/AccountAutocomplete' import CategoryAutocomplete from 'loot-design/src/components/CategorySelect'; import { View, Text, Tooltip, Button } from 'loot-design/src/components/common'; import DateSelect from 'loot-design/src/components/DateSelect'; -import PayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; +import NewPayeeAutocomplete from 'loot-design/src/components/NewPayeeAutocomplete'; +import LegacyPayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; import { Cell, Field, @@ -66,6 +67,7 @@ import ArrowsSynchronize from 'loot-design/src/svg/v2/ArrowsSynchronize'; import CalendarIcon from 'loot-design/src/svg/v2/Calendar'; import Hyperlink2 from 'loot-design/src/svg/v2/Hyperlink2'; +import useFeatureFlag from '../../hooks/useFeatureFlag'; import usePrevious from '../../hooks/usePrevious'; import { getStatusProps } from '../schedules/StatusBadge'; @@ -393,6 +395,7 @@ function PayeeCell({ onCreatePayee, onManagePayees, }) { + const isNewAutocompleteEnabled = useFeatureFlag('newAutocomplete'); let isCreatingPayee = useRef(false); return ( @@ -423,6 +426,9 @@ function PayeeCell({ shouldSaveFromKey, inputStyle, }) => { + const PayeeAutocomplete = isNewAutocompleteEnabled + ? NewPayeeAutocomplete + : LegacyPayeeAutocomplete; return ( <> <PayeeAutocomplete @@ -442,6 +448,7 @@ function PayeeCell({ onUpdate={onUpdate} onSelect={onSave} onManagePayees={() => onManagePayees(payeeId)} + isCreatable /> </> ); diff --git a/packages/desktop-client/src/components/accounts/TransactionsTable.test.js b/packages/desktop-client/src/components/accounts/TransactionsTable.test.js index 08c5da6eea923b53f4913b62ef8dd4c5aed39fdc..5aa96f904b0ca73efd5441bb9792cbb7202baff5 100644 --- a/packages/desktop-client/src/components/accounts/TransactionsTable.test.js +++ b/packages/desktop-client/src/components/accounts/TransactionsTable.test.js @@ -25,6 +25,7 @@ import { SplitsExpandedProvider, TransactionTable } from './TransactionsTable'; const uuid = require('loot-core/src/platform/uuid'); jest.mock('loot-core/src/platform/client/fetch'); +jest.mock('../../hooks/useFeatureFlag', () => jest.fn().mockReturnValue(false)); const accounts = [generateAccount('Bank of America')]; const payees = [ diff --git a/packages/desktop-client/src/components/schedules/EditSchedule.js b/packages/desktop-client/src/components/schedules/EditSchedule.js index 5e61e2373f2f7adc8df5f9e5690529a6a40070a8..c78715e1adefb6528a79ee6be5844416ff4eca1c 100644 --- a/packages/desktop-client/src/components/schedules/EditSchedule.js +++ b/packages/desktop-client/src/components/schedules/EditSchedule.js @@ -16,7 +16,8 @@ import { FormLabel, Checkbox, } from 'loot-design/src/components/forms'; -import PayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; +import NewPayeeAutocomplete from 'loot-design/src/components/NewPayeeAutocomplete'; +import LegacyPayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; import RecurringSchedulePicker from 'loot-design/src/components/RecurringSchedulePicker'; import { SelectedItemsButton } from 'loot-design/src/components/table'; import useSelected, { @@ -24,6 +25,7 @@ import useSelected, { } from 'loot-design/src/components/useSelected'; import { colors } from 'loot-design/src/style'; +import useFeatureFlag from '../../hooks/useFeatureFlag'; import SimpleTransactionsTable from '../accounts/SimpleTransactionsTable'; import { OpSelect } from '../modals/EditRule'; import { Page } from '../Page'; @@ -83,6 +85,8 @@ function updateScheduleConditions(schedule, fields) { } export default function ScheduleDetails() { + const isNewAutocompleteEnabled = useFeatureFlag('newAutocomplete'); + let { id, initialFields } = useParams(); let adding = id == null; let payees = useCachedPayees({ idKey: true }); @@ -420,6 +424,10 @@ export default function ScheduleDetails() { // This is derived from the date let repeats = state.fields.date ? !!state.fields.date.frequency : false; + const PayeeAutocomplete = isNewAutocompleteEnabled + ? NewPayeeAutocomplete + : LegacyPayeeAutocomplete; + return ( <Page title={payee ? `Schedule: ${payee.name}` : 'Schedule'} @@ -434,6 +442,7 @@ export default function ScheduleDetails() { onSelect={id => dispatch({ type: 'set-field', field: 'payee', value: id }) } + isCreatable /> </FormField> diff --git a/packages/desktop-client/src/components/settings/Experimental.js b/packages/desktop-client/src/components/settings/Experimental.js index 60ee158ae5dc73550b6f5d818c81c5f99f4f5f37..e51a325d0f24777885400fe4c73e77b308bcedb8 100644 --- a/packages/desktop-client/src/components/settings/Experimental.js +++ b/packages/desktop-client/src/components/settings/Experimental.js @@ -66,6 +66,18 @@ export default function ExperimentalFeatures({ prefs, savePrefs }) { />{' '} <View>Enable Goal Templates</View> </label> + <label style={{ display: 'flex' }}> + <Checkbox + id="new-autocomplete-flag" + checked={flags.newAutocomplete} + onChange={() => { + savePrefs({ + 'flags.newAutocomplete': !flags.newAutocomplete, + }); + }} + />{' '} + <View>Enable new Autocomplete component</View> + </label> </View> ) : ( <Link diff --git a/packages/desktop-client/src/components/util/GenericInput.js b/packages/desktop-client/src/components/util/GenericInput.js index c8b23fa0fbe74af99c58bbbd29bc6e57ab4596bb..b2307439b30da5be74f58fc2050ced1c3b864a68 100644 --- a/packages/desktop-client/src/components/util/GenericInput.js +++ b/packages/desktop-client/src/components/util/GenericInput.js @@ -8,9 +8,12 @@ import CategoryAutocomplete from 'loot-design/src/components/CategorySelect'; import { View, Input } from 'loot-design/src/components/common'; import DateSelect from 'loot-design/src/components/DateSelect'; import { Checkbox } from 'loot-design/src/components/forms'; -import PayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; +import NewPayeeAutocomplete from 'loot-design/src/components/NewPayeeAutocomplete'; +import LegacyPayeeAutocomplete from 'loot-design/src/components/PayeeAutocomplete'; import RecurringSchedulePicker from 'loot-design/src/components/RecurringSchedulePicker'; +import useFeatureFlag from '../../hooks/useFeatureFlag'; + export default function GenericInput({ field, subfield, @@ -21,6 +24,11 @@ export default function GenericInput({ style, onChange, }) { + const isNewAutocompleteEnabled = useFeatureFlag('newAutocomplete'); + const PayeeAutocomplete = isNewAutocompleteEnabled + ? NewPayeeAutocomplete + : LegacyPayeeAutocomplete; + let { payees, accounts, categoryGroups, dateFormat } = useSelector(state => { return { payees: state.queries.payees, diff --git a/packages/desktop-client/src/hooks/useFeatureFlag.js b/packages/desktop-client/src/hooks/useFeatureFlag.js new file mode 100644 index 0000000000000000000000000000000000000000..4ea6dc4fd5ceea447c56288cc4864afa91ca1e96 --- /dev/null +++ b/packages/desktop-client/src/hooks/useFeatureFlag.js @@ -0,0 +1,5 @@ +import { useSelector } from 'react-redux'; + +export default function useFeatureFlag(name) { + return useSelector(state => state.prefs.local[`flags.${name}`]); +} diff --git a/packages/loot-design/package.json b/packages/loot-design/package.json index e28b01f7e310d522c612939ec34969c7f4728791..ab874e55fcce5c14920545addf60aa53ae0de6b9 100644 --- a/packages/loot-design/package.json +++ b/packages/loot-design/package.json @@ -33,6 +33,7 @@ "react-dnd": "^10.0.2", "react-merge-refs": "^1.1.0", "react-modal": "3.16.1", + "react-select": "^5.7.0", "react-spring": "^8.0.27", "react-virtualized-auto-sizer": "^1.0.2" }, diff --git a/packages/loot-design/src/components/NewPayeeAutocomplete.js b/packages/loot-design/src/components/NewPayeeAutocomplete.js new file mode 100644 index 0000000000000000000000000000000000000000..1812c88e399ce1cc9a2ae287df2b3c98d5d5a62b --- /dev/null +++ b/packages/loot-design/src/components/NewPayeeAutocomplete.js @@ -0,0 +1,241 @@ +import React, { useState, useMemo, useRef } from 'react'; +import { useDispatch } from 'react-redux'; +import Select, { components as SelectComponents } from 'react-select'; + +import Creatable from 'react-select/creatable'; + +import { createPayee } from 'loot-core/src/client/actions/queries'; +import { useCachedAccounts } from 'loot-core/src/client/data-hooks/accounts'; +import { useCachedPayees } from 'loot-core/src/client/data-hooks/payees'; +import { getActivePayees } from 'loot-core/src/client/reducers/queries'; + +import { colors } from '../style'; +import Add from '../svg/v1/Add'; + +import { AutocompleteFooter, AutocompleteFooterButton } from './Autocomplete'; +import styles from './autocomplete-styles'; +import { View, NullComponent } from './common'; + +function getPayeeSuggestions(payees, focusTransferPayees, accounts) { + let activePayees = + (accounts ? getActivePayees(payees, accounts) : payees) || []; + + function formatOptions(options) { + return options.map(row => ({ + value: row.id, + label: row.name, + })); + } + + return [ + ...(focusTransferPayees + ? [] + : [ + { + label: 'Payees', + options: formatOptions(activePayees.filter(p => !p.transfer_acct)), + }, + ]), + { + label: 'Transfer To/From', + options: formatOptions(activePayees.filter(p => p.transfer_acct)), + }, + ]; +} + +function MenuListWithFooter(props) { + return ( + <> + <SelectComponents.MenuList {...props} /> + {props.selectProps.footer} + </> + ); +} + +export default function PayeeAutocomplete({ + value, + focused = false, + showMakeTransfer = true, + showManagePayees = false, + defaultFocusTransferPayees = false, + embedded = false, + multi = false, + isCreatable = false, + onSelect, + onManagePayees, + ...props +}) { + const selectRef = useRef(); + const [initialValue] = useState(value); + const [isOpen, setIsOpen] = useState(focused); + const [inputValue, setInputValue] = useState(); + const payees = useCachedPayees(); + const accounts = useCachedAccounts(); + + const [focusTransferPayees, setFocusTransferPayees] = useState( + defaultFocusTransferPayees, + ); + const options = useMemo( + () => getPayeeSuggestions(payees, focusTransferPayees, accounts), + [payees, focusTransferPayees, accounts], + ); + const allOptions = useMemo( + () => options.reduce((carry, { options }) => [...carry, ...options], []), + [options], + ); + + const dispatch = useDispatch(); + + const onChange = async selected => { + // Clear button clicked + if (!selected) { + onSelect(null); + return; + } + + // Close the menu when making a successful selection + if (!Array.isArray(selected)) { + setIsOpen(false); + } + + const existingOption = allOptions.find(option => + filterOption(option, selected.label), + ); + if (selected.__isNew__) { + // Prevent creating duplicates + if (existingOption) { + onSelect(existingOption.value); + return; + } + + // This is actually a new payee, so create it + onSelect(await dispatch(createPayee(selected.value))); + return; + } + + // Multi-select has multiple selections + if (Array.isArray(selected)) { + onSelect(selected.map(option => option.value)); + return; + } + + onSelect(selected.value); + }; + + const filterOption = (option, input) => { + return ( + option.data?.__isNew__ || + option.label.toLowerCase().includes(input?.toLowerCase()) + ); + }; + + const onKeyDown = event => { + const ESC = 27; + + if (event.keyCode === ESC) { + onSelect(initialValue); + setIsOpen(false); + return; + } + + if (!isOpen) { + setIsOpen(true); + } + }; + + const useCreatableComponent = isCreatable && focusTransferPayees === false; + const Component = useCreatableComponent ? Creatable : Select; + + return ( + <Component + ref={selectRef} + menuIsOpen={isOpen || embedded} + autoFocus={embedded} + options={options} + value={ + multi + ? allOptions.filter(item => value.includes(item.value)) + : allOptions.find(item => item.value === value) + } + inputValue={inputValue} + placeholder="(none)" + captureMenuScroll={false} + onChange={onChange} + onKeyDown={onKeyDown} + onBlur={() => setIsOpen(false)} + onFocus={() => setIsOpen(true)} + onInputChange={setInputValue} + createOptionPosition="first" + formatCreateLabel={inputValue => ( + <View + style={{ + display: 'block', + color: colors.g8, + fontSize: 11, + fontWeight: 500, + marginLeft: -10, + padding: '4px 0', + }} + > + <Add + width={8} + height={8} + style={{ + color: colors.g8, + marginRight: 5, + display: 'inline-block', + }} + /> + Create Payee "{inputValue}" + </View> + )} + isClearable + filterOption={filterOption} + components={{ + MenuList: MenuListWithFooter, + IndicatorSeparator: NullComponent, + DropdownIndicator: NullComponent, + }} + maxMenuHeight={200} + styles={styles} + embedded={embedded} + isMulti={multi} + menuPlacement="auto" + menuPortalTarget={embedded ? undefined : document.body} + footer={ + <AutocompleteFooter show={showMakeTransfer || showManagePayees}> + {showMakeTransfer && ( + <AutocompleteFooterButton + title="Make Transfer" + style={[ + showManagePayees && { marginBottom: 5 }, + focusTransferPayees && { + backgroundColor: colors.y8, + color: colors.g2, + borderColor: colors.y8, + }, + ]} + hoveredStyle={ + focusTransferPayees && { + backgroundColor: colors.y8, + colors: colors.y2, + } + } + onClick={() => { + setInputValue(''); + setFocusTransferPayees(!focusTransferPayees); + }} + /> + )} + {showManagePayees && ( + <AutocompleteFooterButton + title="Manage Payees" + onClick={onManagePayees} + /> + )} + </AutocompleteFooter> + } + {...props} + /> + ); +} diff --git a/packages/loot-design/src/components/autocomplete-styles.js b/packages/loot-design/src/components/autocomplete-styles.js new file mode 100644 index 0000000000000000000000000000000000000000..c2cbb24842773a0a747c13193fff75d26a109153 --- /dev/null +++ b/packages/loot-design/src/components/autocomplete-styles.js @@ -0,0 +1,74 @@ +import { styles as actualStyles, colors } from '../style'; + +const colourStyles = { + ...actualStyles.lightScrollbar, + control: styles => ({ + ...styles, + backgroundColor: 'white', + border: '1px solid rgb(208, 208, 208)', + borderRadius: 4, + outline: 0, + marginLeft: -1, + marginRight: 1, + padding: '5px 3px', + minHeight: 'auto', + }), + input: styles => ({ + ...styles, + padding: 0, + margin: 0, + }), + menuPortal: styles => ({ + ...styles, + zIndex: 5000, + }), + menu: (styles, { selectProps }) => ({ + ...styles, + backgroundColor: colors.n1, + marginTop: 2, + marginBottom: 2, + position: selectProps.embedded ? 'relative' : styles.position, + overflow: 'hidden', + }), + menuList: styles => ({ + ...styles, + padding: 0, + + // Custom scrollbar styling + ...Object.entries(actualStyles.lightScrollbar).reduce( + (carry, [key, value]) => ({ + ...carry, + [key.replace('& ', '')]: value, + }), + {}, + ), + }), + group: styles => ({ + ...styles, + padding: '5px 0 0', + }), + groupHeading: styles => ({ + ...styles, + color: colors.y9, + textTransform: 'none', + paddingLeft: '9px', + fontSize: '100%', + fontWeight: 'normal', + }), + option: (styles, { isFocused }) => ({ + ...styles, + backgroundColor: isFocused ? colors.n5 : undefined, + color: 'white', + padding: '3px 20px', + fontSize: 13, + }), + valueContainer: styles => ({ ...styles, padding: 'none' }), + clearIndicator: styles => ({ + ...styles, + padding: 'none', + '> svg': { height: 15, width: 15 }, + }), + multiValue: styles => ({ ...styles, backgroundColor: colors.b9 }), +}; + +export default colourStyles; diff --git a/packages/loot-design/src/components/common.js b/packages/loot-design/src/components/common.js index deed2fad9d7ebe3acc0febbf0afa2b0fe80f174d..c6bad8b6c489b53a0a91c56e03f11b400ee6becd 100644 --- a/packages/loot-design/src/components/common.js +++ b/packages/loot-design/src/components/common.js @@ -1181,5 +1181,7 @@ export function Label({ title, style }) { ); } +export const NullComponent = () => null; + export * from './tooltips'; export { useTooltip } from './tooltips'; diff --git a/packages/loot-design/src/components/modals/EditField.js b/packages/loot-design/src/components/modals/EditField.js index 606ee6e7d01bb7966075e67f88a12600b4c39fc0..e628a19b52e9f80fd44f5701fe12be509f9a07f1 100644 --- a/packages/loot-design/src/components/modals/EditField.js +++ b/packages/loot-design/src/components/modals/EditField.js @@ -13,8 +13,8 @@ import CategoryAutocomplete from '../CategorySelect'; import { View, Modal, Input } from '../common'; import DateSelect from '../DateSelect'; import { SectionLabel } from '../forms'; -import PayeeAutocomplete from '../PayeeAutocomplete'; -// import { colors } from '../../style'; +import NewPayeeAutocomplete from '../NewPayeeAutocomplete'; +import LegacyPayeeAutocomplete from '../PayeeAutocomplete'; function EditField({ actions, @@ -26,6 +26,7 @@ function EditField({ onSubmit, dateFormat, createPayee, + isNewAutocompleteEnabled, }) { function onSelect(value) { if (value != null) { @@ -46,6 +47,10 @@ function EditField({ containerProps: { style: { height: 275 } }, }; + const PayeeAutocomplete = isNewAutocompleteEnabled + ? NewPayeeAutocomplete + : LegacyPayeeAutocomplete; + switch (name) { case 'date': { let today = currentDay(); @@ -101,6 +106,7 @@ function EditField({ onSelect(value); }} + isCreatable {...autocompleteProps} /> ); @@ -189,6 +195,7 @@ export default connect( categoryGroups: state.queries.categories.grouped, accounts: state.queries.accounts, payees: state.queries.payees, + isNewAutocompleteEnabled: state.prefs.local['flags.newAutocomplete'], }), actions, )(EditField); diff --git a/packages/loot-design/src/components/tooltips.js b/packages/loot-design/src/components/tooltips.js index f386ddc0d3cd1f78dadf70dade3a575e5bdbaa8a..f72ab82abff4e4913ff535c7c7643e1783936701 100644 --- a/packages/loot-design/src/components/tooltips.js +++ b/packages/loot-design/src/components/tooltips.js @@ -45,7 +45,8 @@ export class Tooltip extends React.Component { // kind of things can be click that shouldn't close a tooltip? if ( node.dataset.testid === 'tooltip' || - node.dataset.reachPopover != null + node.dataset.reachPopover != null || + node.id.startsWith('react-select') ) { break; } diff --git a/upcoming-release-notes/741.md b/upcoming-release-notes/741.md new file mode 100644 index 0000000000000000000000000000000000000000..d09ac0f72fda322ad84baed0353164015bc3e27d --- /dev/null +++ b/upcoming-release-notes/741.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Refactored PaymentAutocomplete component to use react-select diff --git a/yarn.lock b/yarn.lock index 32aad432eb365d302d600574634cc31c5dbe74db..06ae57d273b7f6d19b13fa1064548bf1127683b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -328,7 +328,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.18.6": +"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-module-imports@npm:7.18.6" dependencies: @@ -1578,7 +1578,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.21.0 resolution: "@babel/runtime@npm:7.21.0" dependencies: @@ -1862,6 +1862,123 @@ __metadata: languageName: node linkType: hard +"@emotion/babel-plugin@npm:^11.10.6": + version: 11.10.6 + resolution: "@emotion/babel-plugin@npm:11.10.6" + dependencies: + "@babel/helper-module-imports": ^7.16.7 + "@babel/runtime": ^7.18.3 + "@emotion/hash": ^0.9.0 + "@emotion/memoize": ^0.8.0 + "@emotion/serialize": ^1.1.1 + babel-plugin-macros: ^3.1.0 + convert-source-map: ^1.5.0 + escape-string-regexp: ^4.0.0 + find-root: ^1.1.0 + source-map: ^0.5.7 + stylis: 4.1.3 + checksum: 3eed138932e8edf2598352e69ad949b9db3051a4d6fcff190dacbac9aa838d7ef708b9f3e6c48660625d9311dae82d73477ae4e7a31139feef5eb001a5528421 + languageName: node + linkType: hard + +"@emotion/cache@npm:^11.10.5, @emotion/cache@npm:^11.4.0": + version: 11.10.5 + resolution: "@emotion/cache@npm:11.10.5" + dependencies: + "@emotion/memoize": ^0.8.0 + "@emotion/sheet": ^1.2.1 + "@emotion/utils": ^1.2.0 + "@emotion/weak-memoize": ^0.3.0 + stylis: 4.1.3 + checksum: 1dd2d9af2d3ecbd3d4469ecdf91a335eef6034c851b57a474471b2d2280613eb35bbed98c0368cc4625f188619fbdaf04cf07e8107aaffce94b2178444c0fe7b + languageName: node + linkType: hard + +"@emotion/hash@npm:^0.9.0": + version: 0.9.0 + resolution: "@emotion/hash@npm:0.9.0" + checksum: b63428f7c8186607acdca5d003700cecf0ded519d0b5c5cc3b3154eafcad6ff433f8361bd2bac8882715b557e6f06945694aeb6ba8b25c6095d7a88570e2e0bb + languageName: node + linkType: hard + +"@emotion/memoize@npm:^0.8.0": + version: 0.8.0 + resolution: "@emotion/memoize@npm:0.8.0" + checksum: c87bb110b829edd8e1c13b90a6bc37cebc39af29c7599a1e66a48e06f9bec43e8e53495ba86278cc52e7589549492c8dfdc81d19f4fdec0cee6ba13d2ad2c928 + languageName: node + linkType: hard + +"@emotion/react@npm:^11.8.1": + version: 11.10.6 + resolution: "@emotion/react@npm:11.10.6" + dependencies: + "@babel/runtime": ^7.18.3 + "@emotion/babel-plugin": ^11.10.6 + "@emotion/cache": ^11.10.5 + "@emotion/serialize": ^1.1.1 + "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 + "@emotion/utils": ^1.2.0 + "@emotion/weak-memoize": ^0.3.0 + hoist-non-react-statics: ^3.3.1 + peerDependencies: + react: ">=16.8.0" + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 4762042e39126ffaffe76052dc65c9bb0ba6b8893013687ba3cc13ed4dd834c31597f1230684c3c078e90aecc13ab6cd0e3cde0dec8b7761affd2571f4d80019 + languageName: node + linkType: hard + +"@emotion/serialize@npm:^1.1.1": + version: 1.1.1 + resolution: "@emotion/serialize@npm:1.1.1" + dependencies: + "@emotion/hash": ^0.9.0 + "@emotion/memoize": ^0.8.0 + "@emotion/unitless": ^0.8.0 + "@emotion/utils": ^1.2.0 + csstype: ^3.0.2 + checksum: 24cfd5b16e6f2335c032ca33804a876e0442aaf8f9c94d269d23735ebd194fb1ed142542dd92191a3e6ef8bad5bd560dfc5aaf363a1b70954726dbd4dd93085c + languageName: node + linkType: hard + +"@emotion/sheet@npm:^1.2.1": + version: 1.2.1 + resolution: "@emotion/sheet@npm:1.2.1" + checksum: ce78763588ea522438156344d9f592203e2da582d8d67b32e1b0b98eaba26994c6c270f8c7ad46442fc9c0a9f048685d819cd73ca87e544520fd06f0e24a1562 + languageName: node + linkType: hard + +"@emotion/unitless@npm:^0.8.0": + version: 0.8.0 + resolution: "@emotion/unitless@npm:0.8.0" + checksum: 176141117ed23c0eb6e53a054a69c63e17ae532ec4210907a20b2208f91771821835f1c63dd2ec63e30e22fcc984026d7f933773ee6526dd038e0850919fae7a + languageName: node + linkType: hard + +"@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0": + version: 1.0.0 + resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.0" + peerDependencies: + react: ">=16.8.0" + checksum: 4f06a3b48258c832aa8022a262572061a31ff078d377e9164cccc99951309d70f4466e774fe704461b2f8715007a82ed625a54a5c7a127c89017d3ce3187d4f1 + languageName: node + linkType: hard + +"@emotion/utils@npm:^1.2.0": + version: 1.2.0 + resolution: "@emotion/utils@npm:1.2.0" + checksum: 55457a49ddd4db6a014ea0454dc09eaa23eedfb837095c8ff90470cb26a303f7ceb5fcc1e2190ef64683e64cfd33d3ba3ca3109cd87d12bc9e379e4195c9a4dd + languageName: node + linkType: hard + +"@emotion/weak-memoize@npm:^0.3.0": + version: 0.3.0 + resolution: "@emotion/weak-memoize@npm:0.3.0" + checksum: f43ef4c8b7de70d9fa5eb3105921724651e4188e895beb71f0c5919dc899a7b8743e1fdd99d38b9092dd5722c7be2312ebb47fbdad0c4e38bea58f6df5885cc0 + languageName: node + linkType: hard + "@eslint/eslintrc@npm:^2.0.0": version: 2.0.0 resolution: "@eslint/eslintrc@npm:2.0.0" @@ -1886,6 +2003,22 @@ __metadata: languageName: node linkType: hard +"@floating-ui/core@npm:^1.2.3": + version: 1.2.4 + resolution: "@floating-ui/core@npm:1.2.4" + checksum: 1c163ea1804e2b0a28fda6e32efed0e242d0db8081fd24aab9d1cbb100f94a558709231c483bf74bf09a9204ea6e7845813d43b5322ceb6ee63285308f68f65b + languageName: node + linkType: hard + +"@floating-ui/dom@npm:^1.0.1": + version: 1.2.4 + resolution: "@floating-ui/dom@npm:1.2.4" + dependencies: + "@floating-ui/core": ^1.2.3 + checksum: 5c24a2e8f04e436390646c8a4431c6cb79e03711fbb0f818b87d613a6be8971bc560a830b702aaa51a0ebc4d0c45deb06f3140c14125dc1ac770365bf66ee903 + languageName: node + linkType: hard + "@formatjs/ecma402-abstract@npm:1.12.0": version: 1.12.0 resolution: "@formatjs/ecma402-abstract@npm:1.12.0" @@ -3960,6 +4093,15 @@ __metadata: languageName: node linkType: hard +"@types/react-transition-group@npm:^4.4.0": + version: 4.4.5 + resolution: "@types/react-transition-group@npm:4.4.5" + dependencies: + "@types/react": "*" + checksum: 265f1c74061556708ffe8d15559e35c60d6c11478c9950d3735575d2c116ca69f461d85effa06d73a613eb8b73c84fd32682feb57cf7c5f9e4284021dbca25b0 + languageName: node + linkType: hard + "@types/react@npm:*": version: 17.0.43 resolution: "@types/react@npm:17.0.43" @@ -6889,6 +7031,13 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^1.5.0": + version: 1.9.0 + resolution: "convert-source-map@npm:1.9.0" + checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -8099,6 +8248,16 @@ __metadata: languageName: node linkType: hard +"dom-helpers@npm:^5.0.1": + version: 5.2.1 + resolution: "dom-helpers@npm:5.2.1" + dependencies: + "@babel/runtime": ^7.8.7 + csstype: ^3.0.2 + checksum: 863ba9e086f7093df3376b43e74ce4422571d404fc9828bf2c56140963d5edf0e56160f9b2f3bb61b282c07f8fc8134f023c98fd684bddcb12daf7b0f14d951c + languageName: node + linkType: hard + "dom-serializer@npm:0": version: 0.2.2 resolution: "dom-serializer@npm:0.2.2" @@ -9605,6 +9764,13 @@ __metadata: languageName: node linkType: hard +"find-root@npm:^1.1.0": + version: 1.1.0 + resolution: "find-root@npm:1.1.0" + checksum: b2a59fe4b6c932eef36c45a048ae8f93c85640212ebe8363164814990ee20f154197505965f3f4f102efc33bfb1cbc26fd17c4a2fc739ebc51b886b137cbefaf + languageName: node + linkType: hard + "find-up@npm:^2.0.0": version: 2.1.0 resolution: "find-up@npm:2.1.0" @@ -10638,7 +10804,7 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0": +"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -13358,6 +13524,7 @@ __metadata: react-dom: 18.2.0 react-merge-refs: ^1.1.0 react-modal: 3.16.1 + react-select: ^5.7.0 react-spring: ^8.0.27 react-virtualized-auto-sizer: ^1.0.2 wobble: ^1.5.0 @@ -13615,6 +13782,13 @@ __metadata: languageName: node linkType: hard +"memoize-one@npm:^6.0.0": + version: 6.0.0 + resolution: "memoize-one@npm:6.0.0" + checksum: f185ea69f7cceae5d1cb596266dcffccf545e8e7b4106ec6aa93b71ab9d16460dd118ac8b12982c55f6d6322fcc1485de139df07eacffaae94888b9b3ad7675f + languageName: node + linkType: hard + "memory-fs@npm:^0.4.1": version: 0.4.1 resolution: "memory-fs@npm:0.4.1" @@ -17011,6 +17185,26 @@ __metadata: languageName: node linkType: hard +"react-select@npm:^5.7.0": + version: 5.7.0 + resolution: "react-select@npm:5.7.0" + dependencies: + "@babel/runtime": ^7.12.0 + "@emotion/cache": ^11.4.0 + "@emotion/react": ^11.8.1 + "@floating-ui/dom": ^1.0.1 + "@types/react-transition-group": ^4.4.0 + memoize-one: ^6.0.0 + prop-types: ^15.6.0 + react-transition-group: ^4.3.0 + use-isomorphic-layout-effect: ^1.1.2 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 3d29f7bb6dd66ad55396d820f05da6112f1d21b67526422a8ff5aa6cd47c783804c1b73042ac2949ba0871056a3dc68c06a73a8281abb61571e475d72bbd80dc + languageName: node + linkType: hard + "react-spring@npm:^8.0.27": version: 8.0.27 resolution: "react-spring@npm:8.0.27" @@ -17024,6 +17218,21 @@ __metadata: languageName: node linkType: hard +"react-transition-group@npm:^4.3.0": + version: 4.4.5 + resolution: "react-transition-group@npm:4.4.5" + dependencies: + "@babel/runtime": ^7.5.5 + dom-helpers: ^5.0.1 + loose-envify: ^1.4.0 + prop-types: ^15.6.2 + peerDependencies: + react: ">=16.6.0" + react-dom: ">=16.6.0" + checksum: 75602840106aa9c6545149d6d7ae1502fb7b7abadcce70a6954c4b64a438ff1cd16fc77a0a1e5197cdd72da398f39eb929ea06f9005c45b132ed34e056ebdeb1 + languageName: node + linkType: hard + "react-virtualized-auto-sizer@npm:^1.0.2": version: 1.0.6 resolution: "react-virtualized-auto-sizer@npm:1.0.6" @@ -18327,7 +18536,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.5.0, source-map@npm:^0.5.6": +"source-map@npm:^0.5.0, source-map@npm:^0.5.6, source-map@npm:^0.5.7": version: 0.5.7 resolution: "source-map@npm:0.5.7" checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d @@ -18837,6 +19046,13 @@ __metadata: languageName: node linkType: hard +"stylis@npm:4.1.3": + version: 4.1.3 + resolution: "stylis@npm:4.1.3" + checksum: d04dbffcb9bf2c5ca8d8dc09534203c75df3bf711d33973ea22038a99cc475412a350b661ebd99cbc01daa50d7eedcf0d130d121800eb7318759a197023442a6 + languageName: node + linkType: hard + "sumchecker@npm:^3.0.1": version: 3.0.1 resolution: "sumchecker@npm:3.0.1" @@ -19902,6 +20118,18 @@ __metadata: languageName: node linkType: hard +"use-isomorphic-layout-effect@npm:^1.1.2": + version: 1.1.2 + resolution: "use-isomorphic-layout-effect@npm:1.1.2" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: a6532f7fc9ae222c3725ff0308aaf1f1ddbd3c00d685ef9eee6714fd0684de5cb9741b432fbf51e61a784e2955424864f7ea9f99734a02f237b17ad3e18ea5cb + languageName: node + linkType: hard + "use@npm:^3.1.0": version: 3.1.1 resolution: "use@npm:3.1.1"